]> git.proxmox.com Git - ceph.git/blame - ceph/src/civetweb/src/third_party/duktape-1.8.0/src-noline/duktape.c
buildsys: switch source download to quincy
[ceph.git] / ceph / src / civetweb / src / third_party / duktape-1.8.0 / src-noline / duktape.c
CommitLineData
7c673cae 1/*
11fdf7f2
TL
2 * Single source autogenerated distributable for Duktape 1.8.0.
3 *
4 * Git commit 0a70d7e4c5227c84e3fed5209828973117d02849 (v1.8.0).
5 * Git branch v1.8-maintenance.
7c673cae
FG
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*
11fdf7f2 19* Copyright (c) 2013-2017 by Duktape authors (see AUTHORS.rst)
7c673cae
FG
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/* AUTHORS.rst */
40/*
41* ===============
42* Duktape authors
43* ===============
44*
45* Copyright
46* =========
47*
48* Duktape copyrights are held by its authors. Each author has a copyright
49* to their contribution, and agrees to irrevocably license the contribution
50* under the Duktape ``LICENSE.txt``.
51*
52* Authors
53* =======
54*
55* Please include an e-mail address, a link to your GitHub profile, or something
56* similar to allow your contribution to be identified accurately.
57*
58* The following people have contributed code, website contents, or Wiki contents,
59* and agreed to irrevocably license their contributions under the Duktape
60* ``LICENSE.txt`` (in order of appearance):
61*
62* * Sami Vaarala <sami.vaarala@iki.fi>
63* * Niki Dobrev
64* * Andreas \u00d6man <andreas@lonelycoder.com>
65* * L\u00e1szl\u00f3 Lang\u00f3 <llango.u-szeged@partner.samsung.com>
66* * Legimet <legimet.calc@gmail.com>
67* * Karl Skomski <karl@skomski.com>
68* * Bruce Pascoe <fatcerberus1@gmail.com>
11fdf7f2
TL
69* * Ren\u00e9 Hollander <rene@rene8888.at>
70* * Julien Hamaide (https://github.com/crazyjul)
71* * Sebastian G\u00f6tte (https://github.com/jaseg)
7c673cae
FG
72*
73* Other contributions
74* ===================
75*
76* The following people have contributed something other than code (e.g. reported
77* bugs, provided ideas, etc; roughly in order of appearance):
78*
79* * Greg Burns
80* * Anthony Rabine
81* * Carlos Costa
82* * Aur\u00e9lien Bouilland
83* * Preet Desai (Pris Matic)
84* * judofyr (http://www.reddit.com/user/judofyr)
85* * Jason Woofenden
86* * Micha\u0142 Przyby\u015b
87* * Anthony Howe
88* * Conrad Pankoff
89* * Jim Schimpf
90* * Rajaran Gaunker (https://github.com/zimbabao)
91* * Andreas \u00d6man
92* * Doug Sanden
93* * Josh Engebretson (https://github.com/JoshEngebretson)
94* * Remo Eichenberger (https://github.com/remoe)
95* * Mamod Mehyar (https://github.com/mamod)
96* * David Demelier (https://github.com/markand)
97* * Tim Caswell (https://github.com/creationix)
98* * Mitchell Blank Jr (https://github.com/mitchblank)
99* * https://github.com/yushli
100* * Seo Sanghyeon (https://github.com/sanxiyn)
101* * Han ChoongWoo (https://github.com/tunz)
102* * Joshua Peek (https://github.com/josh)
103* * Bruce E. Pascoe (https://github.com/fatcerberus)
104* * https://github.com/Kelledin
105* * https://github.com/sstruchtrup
106* * Michael Drake (https://github.com/tlsa)
107* * https://github.com/chris-y
11fdf7f2
TL
108* * Laurent Zubiaur (https://github.com/lzubiaur)
109* * Ole Andr\u00e9 Vadla Ravn\u00e5s (https://github.com/oleavr)
7c673cae
FG
110*
111* If you are accidentally missing from this list, send me an e-mail
112* (``sami.vaarala@iki.fi``) and I'll fix the omission.
113*/
7c673cae
FG
114/*
115 * Top-level include file to be used for all (internal) source files.
116 *
117 * Source files should not include individual header files, as they
118 * have not been designed to be individually included.
119 */
120
121#ifndef DUK_INTERNAL_H_INCLUDED
122#define DUK_INTERNAL_H_INCLUDED
123
124/*
125 * The 'duktape.h' header provides the public API, but also handles all
126 * compiler and platform specific feature detection, Duktape feature
127 * resolution, inclusion of system headers, etc. These have been merged
128 * because the public API is also dependent on e.g. detecting appropriate
129 * C types which is quite platform/compiler specific especially for a non-C99
130 * build. The public API is also dependent on the resolved feature set.
131 *
132 * Some actions taken by the merged header (such as including system headers)
133 * are not appropriate for building a user application. The define
134 * DUK_COMPILING_DUKTAPE allows the merged header to skip/include some
135 * sections depending on what is being built.
136 */
137
138#define DUK_COMPILING_DUKTAPE
139#include "duktape.h"
140
141/*
142 * User declarations, e.g. prototypes for user functions used by Duktape
143 * macros. Concretely, if DUK_USE_PANIC_HANDLER is used and the macro
144 * value calls a user function, it needs to be declared for Duktape
145 * compilation to avoid warnings.
146 */
147
148DUK_USE_USER_DECLARE()
149
150/*
151 * Duktape includes (other than duk_features.h)
152 *
153 * The header files expect to be included in an order which satisfies header
154 * dependencies correctly (the headers themselves don't include any other
155 * includes). Forward declarations are used to break circular struct/typedef
156 * dependencies.
157 */
158
7c673cae
FG
159#ifndef DUK_REPLACEMENTS_H_INCLUDED
160#define DUK_REPLACEMENTS_H_INCLUDED
161
11fdf7f2
TL
162#if !defined(DUK_SINGLE_FILE)
163#if defined(DUK_USE_COMPUTED_INFINITY)
164DUK_INTERNAL_DECL double duk_computed_infinity;
165#endif
166#if defined(DUK_USE_COMPUTED_NAN)
167DUK_INTERNAL_DECL double duk_computed_nan;
168#endif
169#if defined(DUK_USE_REPL_FPCLASSIFY)
7c673cae
FG
170DUK_INTERNAL_DECL int duk_repl_fpclassify(double x);
171#endif
11fdf7f2 172#if defined(DUK_USE_REPL_SIGNBIT)
7c673cae
FG
173DUK_INTERNAL_DECL int duk_repl_signbit(double x);
174#endif
11fdf7f2 175#if defined(DUK_USE_REPL_ISFINITE)
7c673cae
FG
176DUK_INTERNAL_DECL int duk_repl_isfinite(double x);
177#endif
11fdf7f2 178#if defined(DUK_USE_REPL_ISNAN)
7c673cae
FG
179DUK_INTERNAL_DECL int duk_repl_isnan(double x);
180#endif
11fdf7f2 181#if defined(DUK_USE_REPL_ISINF)
7c673cae
FG
182DUK_INTERNAL_DECL int duk_repl_isinf(double x);
183#endif
11fdf7f2 184#endif /* !DUK_SINGLE_FILE */
7c673cae
FG
185
186#endif /* DUK_REPLACEMENTS_H_INCLUDED */
7c673cae
FG
187/*
188 * Wrapper for jmp_buf.
189 *
190 * This is used because jmp_buf is an array type for backward compatibility.
191 * Wrapping jmp_buf in a struct makes pointer references, sizeof, etc,
192 * behave more intuitively.
193 *
194 * http://en.wikipedia.org/wiki/Setjmp.h#Member_types
195 */
196
197#ifndef DUK_JMPBUF_H_INCLUDED
198#define DUK_JMPBUF_H_INCLUDED
199
11fdf7f2 200#if defined(DUK_USE_CPP_EXCEPTIONS)
7c673cae 201struct duk_jmpbuf {
11fdf7f2
TL
202 duk_small_int_t dummy; /* unused */
203};
7c673cae 204#else
11fdf7f2
TL
205struct duk_jmpbuf {
206 DUK_JMPBUF_TYPE jb;
7c673cae 207};
11fdf7f2 208#endif
7c673cae
FG
209
210#endif /* DUK_JMPBUF_H_INCLUDED */
11fdf7f2
TL
211/*
212 * Exception for Duktape internal throws when C++ exceptions are used
213 * for long control transfers.
214 *
215 * Doesn't inherit from any exception base class to minimize the chance
216 * that user code would accidentally catch this exception.
217 */
218
219#ifndef DUK_EXCEPTION_H_INCLUDED
220#define DUK_EXCEPTION_H_INCLUDED
221
222#if defined(DUK_USE_CPP_EXCEPTIONS)
223class duk_internal_exception {
224 /* intentionally empty */
225};
226#endif
227
228#endif /* DUK_EXCEPTION_H_INCLUDED */
7c673cae
FG
229/*
230 * Forward declarations for all Duktape structures.
231 */
232
233#ifndef DUK_FORWDECL_H_INCLUDED
234#define DUK_FORWDECL_H_INCLUDED
235
236/*
237 * Forward declarations
238 */
239
11fdf7f2
TL
240#if defined(DUK_USE_CPP_EXCEPTIONS)
241class duk_internal_exception;
242#else
7c673cae 243struct duk_jmpbuf;
11fdf7f2 244#endif
7c673cae
FG
245
246/* duk_tval intentionally skipped */
247struct duk_heaphdr;
248struct duk_heaphdr_string;
249struct duk_hstring;
250struct duk_hstring_external;
251struct duk_hobject;
252struct duk_hcompiledfunction;
253struct duk_hnativefunction;
254struct duk_hthread;
255struct duk_hbufferobject;
256struct duk_hbuffer;
257struct duk_hbuffer_fixed;
258struct duk_hbuffer_dynamic;
259struct duk_hbuffer_external;
260
261struct duk_propaccessor;
262union duk_propvalue;
263struct duk_propdesc;
264
265struct duk_heap;
266struct duk_breakpoint;
267
268struct duk_activation;
269struct duk_catcher;
270struct duk_strcache;
271struct duk_ljstate;
272struct duk_strtab_entry;
273
274#ifdef DUK_USE_DEBUG
275struct duk_fixedbuffer;
276#endif
277
278struct duk_bitdecoder_ctx;
279struct duk_bitencoder_ctx;
280struct duk_bufwriter_ctx;
281
282struct duk_token;
283struct duk_re_token;
284struct duk_lexer_point;
285struct duk_lexer_ctx;
286struct duk_lexer_codepoint;
287
288struct duk_compiler_instr;
289struct duk_compiler_func;
290struct duk_compiler_ctx;
291
292struct duk_re_matcher_ctx;
293struct duk_re_compiler_ctx;
294
11fdf7f2
TL
295#if defined(DUK_USE_CPP_EXCEPTIONS)
296/* no typedef */
297#else
7c673cae 298typedef struct duk_jmpbuf duk_jmpbuf;
11fdf7f2 299#endif
7c673cae
FG
300
301/* duk_tval intentionally skipped */
302typedef struct duk_heaphdr duk_heaphdr;
303typedef struct duk_heaphdr_string duk_heaphdr_string;
304typedef struct duk_hstring duk_hstring;
305typedef struct duk_hstring_external duk_hstring_external;
306typedef struct duk_hobject duk_hobject;
307typedef struct duk_hcompiledfunction duk_hcompiledfunction;
308typedef struct duk_hnativefunction duk_hnativefunction;
309typedef struct duk_hbufferobject duk_hbufferobject;
310typedef struct duk_hthread duk_hthread;
311typedef struct duk_hbuffer duk_hbuffer;
312typedef struct duk_hbuffer_fixed duk_hbuffer_fixed;
313typedef struct duk_hbuffer_dynamic duk_hbuffer_dynamic;
314typedef struct duk_hbuffer_external duk_hbuffer_external;
315
316typedef struct duk_propaccessor duk_propaccessor;
317typedef union duk_propvalue duk_propvalue;
318typedef struct duk_propdesc duk_propdesc;
319
320typedef struct duk_heap duk_heap;
321typedef struct duk_breakpoint duk_breakpoint;
322
323typedef struct duk_activation duk_activation;
324typedef struct duk_catcher duk_catcher;
325typedef struct duk_strcache duk_strcache;
326typedef struct duk_ljstate duk_ljstate;
327typedef struct duk_strtab_entry duk_strtab_entry;
328
329#ifdef DUK_USE_DEBUG
330typedef struct duk_fixedbuffer duk_fixedbuffer;
331#endif
332
333typedef struct duk_bitdecoder_ctx duk_bitdecoder_ctx;
334typedef struct duk_bitencoder_ctx duk_bitencoder_ctx;
335typedef struct duk_bufwriter_ctx duk_bufwriter_ctx;
336
337typedef struct duk_token duk_token;
338typedef struct duk_re_token duk_re_token;
339typedef struct duk_lexer_point duk_lexer_point;
340typedef struct duk_lexer_ctx duk_lexer_ctx;
341typedef struct duk_lexer_codepoint duk_lexer_codepoint;
342
343typedef struct duk_compiler_instr duk_compiler_instr;
344typedef struct duk_compiler_func duk_compiler_func;
345typedef struct duk_compiler_ctx duk_compiler_ctx;
346
347typedef struct duk_re_matcher_ctx duk_re_matcher_ctx;
348typedef struct duk_re_compiler_ctx duk_re_compiler_ctx;
349
350#endif /* DUK_FORWDECL_H_INCLUDED */
7c673cae 351/*
11fdf7f2
TL
352 * Tagged type definition (duk_tval) and accessor macros.
353 *
354 * Access all fields through the accessor macros, as the representation
355 * is quite tricky.
356 *
357 * There are two packed type alternatives: an 8-byte representation
358 * based on an IEEE double (preferred for compactness), and a 12-byte
359 * representation (portability). The latter is needed also in e.g.
360 * 64-bit environments (it usually pads to 16 bytes per value).
361 *
362 * Selecting the tagged type format involves many trade-offs (memory
363 * use, size and performance of generated code, portability, etc),
364 * see doc/types.rst for a detailed discussion (especially of how the
365 * IEEE double format is used to pack tagged values).
366 *
367 * NB: because macro arguments are often expressions, macros should
368 * avoid evaluating their argument more than once.
7c673cae
FG
369 */
370
11fdf7f2
TL
371#ifndef DUK_TVAL_H_INCLUDED
372#define DUK_TVAL_H_INCLUDED
7c673cae 373
11fdf7f2
TL
374/* sanity */
375#if !defined(DUK_USE_DOUBLE_LE) && !defined(DUK_USE_DOUBLE_ME) && !defined(DUK_USE_DOUBLE_BE)
376#error unsupported: cannot determine byte order variant
377#endif
7c673cae 378
11fdf7f2
TL
379#if defined(DUK_USE_PACKED_TVAL)
380/* ======================================================================== */
7c673cae 381
11fdf7f2
TL
382/*
383 * Packed 8-byte representation
384 */
7c673cae 385
11fdf7f2
TL
386/* use duk_double_union as duk_tval directly */
387typedef union duk_double_union duk_tval;
7c673cae 388
11fdf7f2
TL
389/* tags */
390#define DUK_TAG_NORMALIZED_NAN 0x7ff8UL /* the NaN variant we use */
391/* avoid tag 0xfff0, no risk of confusion with negative infinity */
392#if defined(DUK_USE_FASTINT)
393#define DUK_TAG_FASTINT 0xfff1UL /* embed: integer value */
394#endif
395#define DUK_TAG_UNUSED 0xfff2UL /* marker; not actual tagged value */
396#define DUK_TAG_UNDEFINED 0xfff3UL /* embed: nothing */
397#define DUK_TAG_NULL 0xfff4UL /* embed: nothing */
398#define DUK_TAG_BOOLEAN 0xfff5UL /* embed: 0 or 1 (false or true) */
399/* DUK_TAG_NUMBER would logically go here, but it has multiple 'tags' */
400#define DUK_TAG_POINTER 0xfff6UL /* embed: void ptr */
401#define DUK_TAG_LIGHTFUNC 0xfff7UL /* embed: func ptr */
402#define DUK_TAG_STRING 0xfff8UL /* embed: duk_hstring ptr */
403#define DUK_TAG_OBJECT 0xfff9UL /* embed: duk_hobject ptr */
404#define DUK_TAG_BUFFER 0xfffaUL /* embed: duk_hbuffer ptr */
7c673cae 405
11fdf7f2
TL
406/* for convenience */
407#define DUK_XTAG_BOOLEAN_FALSE 0xfff50000UL
408#define DUK_XTAG_BOOLEAN_TRUE 0xfff50001UL
7c673cae 409
11fdf7f2
TL
410/* two casts to avoid gcc warning: "warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]" */
411#if defined(DUK_USE_64BIT_OPS)
412#if defined(DUK_USE_DOUBLE_ME)
413#define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag) do { \
414 (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 16) | (((duk_uint64_t) (duk_uint32_t) (h)) << 32); \
415 } while (0)
416#else
417#define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag) do { \
418 (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 48) | ((duk_uint64_t) (duk_uint32_t) (h)); \
419 } while (0)
420#endif
421#else /* DUK_USE_64BIT_OPS */
422#define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag) do { \
423 (v)->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) (tag)) << 16; \
424 (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (h); \
425 } while (0)
426#endif /* DUK_USE_64BIT_OPS */
7c673cae 427
11fdf7f2
TL
428#if defined(DUK_USE_64BIT_OPS)
429/* Double casting for pointer to avoid gcc warning (cast from pointer to integer of different size) */
430#if defined(DUK_USE_DOUBLE_ME)
431#define DUK__TVAL_SET_LIGHTFUNC(v,fp,flags) do { \
432 (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 16) | \
433 ((duk_uint64_t) (flags)) | \
434 (((duk_uint64_t) (duk_uint32_t) (fp)) << 32); \
435 } while (0)
436#else
437#define DUK__TVAL_SET_LIGHTFUNC(v,fp,flags) do { \
438 (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 48) | \
439 (((duk_uint64_t) (flags)) << 32) | \
440 ((duk_uint64_t) (duk_uint32_t) (fp)); \
441 } while (0)
442#endif
443#else /* DUK_USE_64BIT_OPS */
444#define DUK__TVAL_SET_LIGHTFUNC(v,fp,flags) do { \
445 (v)->ui[DUK_DBL_IDX_UI0] = (((duk_uint32_t) DUK_TAG_LIGHTFUNC) << 16) | ((duk_uint32_t) (flags)); \
446 (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (fp); \
447 } while (0)
448#endif /* DUK_USE_64BIT_OPS */
7c673cae 449
11fdf7f2
TL
450#if defined(DUK_USE_FASTINT)
451/* Note: masking is done for 'i' to deal with negative numbers correctly */
452#if defined(DUK_USE_DOUBLE_ME)
453#define DUK__TVAL_SET_FASTINT(v,i) do { \
454 (v)->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16 | (((duk_uint32_t) ((i) >> 32)) & 0x0000ffffUL); \
455 (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \
456 } while (0)
457#define DUK__TVAL_SET_FASTINT_U32(v,i) do { \
458 (v)->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16; \
459 (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \
460 } while (0)
461#else
462#define DUK__TVAL_SET_FASTINT(v,i) do { \
463 (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (((duk_uint64_t) (i)) & 0x0000ffffffffffffULL); \
464 } while (0)
465#define DUK__TVAL_SET_FASTINT_U32(v,i) do { \
466 (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (duk_uint64_t) (i); \
467 } while (0)
468#endif
7c673cae 469
11fdf7f2
TL
470#define DUK__TVAL_SET_FASTINT_I32(v,i) do { \
471 duk_int64_t duk__tmp = (duk_int64_t) (i); \
472 DUK_TVAL_SET_FASTINT((v), duk__tmp); \
473 } while (0)
474
475/* XXX: clumsy sign extend and masking of 16 topmost bits */
476#if defined(DUK_USE_DOUBLE_ME)
477#define DUK__TVAL_GET_FASTINT(v) (((duk_int64_t) ((((duk_uint64_t) (v)->ui[DUK_DBL_IDX_UI0]) << 32) | ((duk_uint64_t) (v)->ui[DUK_DBL_IDX_UI1]))) << 16 >> 16)
478#else
479#define DUK__TVAL_GET_FASTINT(v) ((((duk_int64_t) (v)->ull[DUK_DBL_IDX_ULL0]) << 16) >> 16)
480#endif
481#define DUK__TVAL_GET_FASTINT_U32(v) ((v)->ui[DUK_DBL_IDX_UI1])
482#define DUK__TVAL_GET_FASTINT_I32(v) ((duk_int32_t) (v)->ui[DUK_DBL_IDX_UI1])
483#endif /* DUK_USE_FASTINT */
484
485#define DUK_TVAL_SET_UNDEFINED(v) do { \
486 (v)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNDEFINED; \
487 } while (0)
488#define DUK_TVAL_SET_UNUSED(v) do { \
489 (v)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNUSED; \
490 } while (0)
491#define DUK_TVAL_SET_NULL(v) do { \
492 (v)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_NULL; \
493 } while (0)
494
495#define DUK_TVAL_SET_BOOLEAN(v,val) DUK_DBLUNION_SET_HIGH32((v), (((duk_uint32_t) DUK_TAG_BOOLEAN) << 16) | ((duk_uint32_t) (val)))
496
497#define DUK_TVAL_SET_NAN(v) DUK_DBLUNION_SET_NAN_FULL((v))
498
499/* Assumes that caller has normalized NaNs, otherwise trouble ahead. */
500#if defined(DUK_USE_FASTINT)
501#define DUK_TVAL_SET_DOUBLE(v,d) do { \
502 duk_double_t duk__dblval; \
503 duk__dblval = (d); \
504 DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \
505 DUK_DBLUNION_SET_DOUBLE((v), duk__dblval); \
506 } while (0)
507#define DUK_TVAL_SET_FASTINT(v,i) DUK__TVAL_SET_FASTINT((v), (i))
508#define DUK_TVAL_SET_FASTINT_I32(v,i) DUK__TVAL_SET_FASTINT_I32((v), (i))
509#define DUK_TVAL_SET_FASTINT_U32(v,i) DUK__TVAL_SET_FASTINT_U32((v), (i))
510#define DUK_TVAL_SET_NUMBER_CHKFAST(v,d) duk_tval_set_number_chkfast((v), (d))
511#define DUK_TVAL_SET_NUMBER(v,d) DUK_TVAL_SET_DOUBLE((v), (d))
512#define DUK_TVAL_CHKFAST_INPLACE(v) do { \
513 duk_tval *duk__tv; \
514 duk_double_t duk__d; \
515 duk__tv = (v); \
516 if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \
517 duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \
518 DUK_TVAL_SET_NUMBER_CHKFAST(duk__tv, duk__d); \
519 } \
520 } while (0)
521#else
522#define DUK_TVAL_SET_DOUBLE(v,d) do { \
523 duk_double_t duk__dblval; \
524 duk__dblval = (d); \
525 DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \
526 DUK_DBLUNION_SET_DOUBLE((v), duk__dblval); \
527 } while (0)
528#define DUK_TVAL_SET_FASTINT(v,i) DUK_TVAL_SET_DOUBLE((v), (duk_double_t) (i)) /* XXX: fast int-to-double */
529#define DUK_TVAL_SET_FASTINT_I32(v,i) DUK_TVAL_SET_DOUBLE((v), (duk_double_t) (i))
530#define DUK_TVAL_SET_FASTINT_U32(v,i) DUK_TVAL_SET_DOUBLE((v), (duk_double_t) (i))
531#define DUK_TVAL_SET_NUMBER_CHKFAST(v,d) DUK_TVAL_SET_DOUBLE((v), (d))
532#define DUK_TVAL_SET_NUMBER(v,d) DUK_TVAL_SET_DOUBLE((v), (d))
533#define DUK_TVAL_CHKFAST_INPLACE(v) do { } while (0)
534#endif
535
536#define DUK_TVAL_SET_LIGHTFUNC(v,fp,flags) DUK__TVAL_SET_LIGHTFUNC((v), (fp), (flags))
537#define DUK_TVAL_SET_STRING(v,h) DUK__TVAL_SET_TAGGEDPOINTER((v), (h), DUK_TAG_STRING)
538#define DUK_TVAL_SET_OBJECT(v,h) DUK__TVAL_SET_TAGGEDPOINTER((v), (h), DUK_TAG_OBJECT)
539#define DUK_TVAL_SET_BUFFER(v,h) DUK__TVAL_SET_TAGGEDPOINTER((v), (h), DUK_TAG_BUFFER)
540#define DUK_TVAL_SET_POINTER(v,p) DUK__TVAL_SET_TAGGEDPOINTER((v), (p), DUK_TAG_POINTER)
541
542#define DUK_TVAL_SET_TVAL(v,x) do { *(v) = *(x); } while (0)
543
544/* getters */
545#define DUK_TVAL_GET_BOOLEAN(v) ((int) (v)->us[DUK_DBL_IDX_US1])
546#if defined(DUK_USE_FASTINT)
547#define DUK_TVAL_GET_DOUBLE(v) ((v)->d)
548#define DUK_TVAL_GET_FASTINT(v) DUK__TVAL_GET_FASTINT((v))
549#define DUK_TVAL_GET_FASTINT_U32(v) DUK__TVAL_GET_FASTINT_U32((v))
550#define DUK_TVAL_GET_FASTINT_I32(v) DUK__TVAL_GET_FASTINT_I32((v))
551#define DUK_TVAL_GET_NUMBER(v) duk_tval_get_number_packed((v))
552#else
553#define DUK_TVAL_GET_NUMBER(v) ((v)->d)
554#define DUK_TVAL_GET_DOUBLE(v) ((v)->d)
555#endif
556#define DUK_TVAL_GET_LIGHTFUNC(v,out_fp,out_flags) do { \
557 (out_flags) = (v)->ui[DUK_DBL_IDX_UI0] & 0xffffUL; \
558 (out_fp) = (duk_c_function) (v)->ui[DUK_DBL_IDX_UI1]; \
559 } while (0)
560#define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(v) ((duk_c_function) ((v)->ui[DUK_DBL_IDX_UI1]))
561#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(v) (((int) (v)->ui[DUK_DBL_IDX_UI0]) & 0xffffUL)
562#define DUK_TVAL_GET_STRING(v) ((duk_hstring *) (v)->vp[DUK_DBL_IDX_VP1])
563#define DUK_TVAL_GET_OBJECT(v) ((duk_hobject *) (v)->vp[DUK_DBL_IDX_VP1])
564#define DUK_TVAL_GET_BUFFER(v) ((duk_hbuffer *) (v)->vp[DUK_DBL_IDX_VP1])
565#define DUK_TVAL_GET_POINTER(v) ((void *) (v)->vp[DUK_DBL_IDX_VP1])
566#define DUK_TVAL_GET_HEAPHDR(v) ((duk_heaphdr *) (v)->vp[DUK_DBL_IDX_VP1])
567
568/* decoding */
569#define DUK_TVAL_GET_TAG(v) ((duk_small_uint_t) (v)->us[DUK_DBL_IDX_US0])
570
571#define DUK_TVAL_IS_UNDEFINED(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_UNDEFINED)
572#define DUK_TVAL_IS_UNUSED(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_UNUSED)
573#define DUK_TVAL_IS_NULL(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_NULL)
574#define DUK_TVAL_IS_BOOLEAN(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_BOOLEAN)
575#define DUK_TVAL_IS_BOOLEAN_TRUE(v) ((v)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_TRUE)
576#define DUK_TVAL_IS_BOOLEAN_FALSE(v) ((v)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_FALSE)
577#define DUK_TVAL_IS_LIGHTFUNC(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_LIGHTFUNC)
578#define DUK_TVAL_IS_STRING(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_STRING)
579#define DUK_TVAL_IS_OBJECT(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_OBJECT)
580#define DUK_TVAL_IS_BUFFER(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_BUFFER)
581#define DUK_TVAL_IS_POINTER(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_POINTER)
582#if defined(DUK_USE_FASTINT)
583/* 0xfff0 is -Infinity */
584#define DUK_TVAL_IS_DOUBLE(v) (DUK_TVAL_GET_TAG((v)) <= 0xfff0UL)
585#define DUK_TVAL_IS_FASTINT(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_FASTINT)
586#define DUK_TVAL_IS_NUMBER(v) (DUK_TVAL_GET_TAG((v)) <= 0xfff1UL)
587#else
588#define DUK_TVAL_IS_NUMBER(v) (DUK_TVAL_GET_TAG((v)) <= 0xfff0UL)
589#define DUK_TVAL_IS_DOUBLE(v) DUK_TVAL_IS_NUMBER((v))
590#endif
591
592/* This is performance critical because it appears in every DECREF. */
593#define DUK_TVAL_IS_HEAP_ALLOCATED(v) (DUK_TVAL_GET_TAG((v)) >= DUK_TAG_STRING)
594
595#if defined(DUK_USE_FASTINT)
596DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_packed(duk_tval *tv);
597#endif
598
599#else /* DUK_USE_PACKED_TVAL */
600/* ======================================================================== */
601
602/*
603 * Portable 12-byte representation
604 */
605
606/* Note: not initializing all bytes is normally not an issue: Duktape won't
607 * read or use the uninitialized bytes so valgrind won't issue warnings.
608 * In some special cases a harmless valgrind warning may be issued though.
609 * For example, the DumpHeap debugger command writes out a compiled function's
610 * 'data' area as is, including any uninitialized bytes, which causes a
611 * valgrind warning.
612 */
613
614typedef struct duk_tval_struct duk_tval;
615
616struct duk_tval_struct {
617 duk_small_uint_t t;
618 duk_small_uint_t v_extra;
619 union {
620 duk_double_t d;
621 duk_small_int_t i;
622#if defined(DUK_USE_FASTINT)
623 duk_int64_t fi; /* if present, forces 16-byte duk_tval */
624#endif
625 void *voidptr;
626 duk_hstring *hstring;
627 duk_hobject *hobject;
628 duk_hcompiledfunction *hcompiledfunction;
629 duk_hnativefunction *hnativefunction;
630 duk_hthread *hthread;
631 duk_hbuffer *hbuffer;
632 duk_heaphdr *heaphdr;
633 duk_c_function lightfunc;
634 } v;
635};
7c673cae 636
11fdf7f2
TL
637#define DUK__TAG_NUMBER 0 /* not exposed */
638#if defined(DUK_USE_FASTINT)
639#define DUK_TAG_FASTINT 1
640#endif
641#define DUK_TAG_UNDEFINED 2
642#define DUK_TAG_NULL 3
643#define DUK_TAG_BOOLEAN 4
644#define DUK_TAG_POINTER 5
645#define DUK_TAG_LIGHTFUNC 6
646#define DUK_TAG_UNUSED 7 /* marker; not actual tagged type */
647#define DUK_TAG_STRING 8 /* first heap allocated, match bit boundary */
648#define DUK_TAG_OBJECT 9
649#define DUK_TAG_BUFFER 10
7c673cae 650
11fdf7f2
TL
651/* DUK__TAG_NUMBER is intentionally first, as it is the default clause in code
652 * to support the 8-byte representation. Further, it is a non-heap-allocated
653 * type so it should come before DUK_TAG_STRING. Finally, it should not break
654 * the tag value ranges covered by case-clauses in a switch-case.
655 */
7c673cae 656
11fdf7f2
TL
657/* setters */
658#define DUK_TVAL_SET_UNDEFINED(tv) do { \
659 (tv)->t = DUK_TAG_UNDEFINED; \
660 } while (0)
7c673cae 661
11fdf7f2
TL
662#define DUK_TVAL_SET_UNUSED(tv) do { \
663 (tv)->t = DUK_TAG_UNUSED; \
664 } while (0)
7c673cae 665
11fdf7f2
TL
666#define DUK_TVAL_SET_NULL(tv) do { \
667 (tv)->t = DUK_TAG_NULL; \
668 } while (0)
7c673cae 669
11fdf7f2
TL
670#define DUK_TVAL_SET_BOOLEAN(tv,val) do { \
671 (tv)->t = DUK_TAG_BOOLEAN; \
672 (tv)->v.i = (val); \
673 } while (0)
7c673cae 674
11fdf7f2
TL
675#if defined(DUK_USE_FASTINT)
676#define DUK_TVAL_SET_DOUBLE(tv,val) do { \
677 (tv)->t = DUK__TAG_NUMBER; \
678 (tv)->v.d = (val); \
679 } while (0)
680#define DUK_TVAL_SET_FASTINT(tv,val) do { \
681 (tv)->t = DUK_TAG_FASTINT; \
682 (tv)->v.fi = (val); \
683 } while (0)
684#define DUK_TVAL_SET_FASTINT_U32(tv,val) do { \
685 (tv)->t = DUK_TAG_FASTINT; \
686 (tv)->v.fi = (duk_int64_t) (val); \
687 } while (0)
688#define DUK_TVAL_SET_FASTINT_I32(tv,val) do { \
689 (tv)->t = DUK_TAG_FASTINT; \
690 (tv)->v.fi = (duk_int64_t) (val); \
691 } while (0)
692#define DUK_TVAL_SET_NUMBER_CHKFAST(tv,d) \
693 duk_tval_set_number_chkfast((tv), (d))
694#define DUK_TVAL_SET_NUMBER(tv,val) \
695 DUK_TVAL_SET_DOUBLE((tv), (val))
696#define DUK_TVAL_CHKFAST_INPLACE(v) do { \
697 duk_tval *duk__tv; \
698 duk_double_t duk__d; \
699 duk__tv = (v); \
700 if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \
701 duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \
702 DUK_TVAL_SET_NUMBER_CHKFAST(duk__tv, duk__d); \
703 } \
704 } while (0)
705#else
706#define DUK_TVAL_SET_DOUBLE(tv,d) \
707 DUK_TVAL_SET_NUMBER((tv), (d))
708#define DUK_TVAL_SET_FASTINT(tv,val) \
709 DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val)) /* XXX: fast int-to-double */
710#define DUK_TVAL_SET_FASTINT_U32(tv,val) \
711 DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val))
712#define DUK_TVAL_SET_FASTINT_I32(tv,val) \
713 DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val))
714#define DUK_TVAL_SET_NUMBER(tv,val) do { \
715 (tv)->t = DUK__TAG_NUMBER; \
716 (tv)->v.d = (val); \
717 } while (0)
718#define DUK_TVAL_SET_NUMBER_CHKFAST(tv,d) \
719 DUK_TVAL_SET_NUMBER((tv), (d))
720#define DUK_TVAL_CHKFAST_INPLACE(v) do { } while (0)
721#endif /* DUK_USE_FASTINT */
7c673cae 722
11fdf7f2
TL
723#define DUK_TVAL_SET_POINTER(tv,hptr) do { \
724 (tv)->t = DUK_TAG_POINTER; \
725 (tv)->v.voidptr = (hptr); \
726 } while (0)
727
728#define DUK_TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \
729 (tv)->t = DUK_TAG_LIGHTFUNC; \
730 (tv)->v_extra = (flags); \
731 (tv)->v.lightfunc = (duk_c_function) (fp); \
732 } while (0)
733
734#define DUK_TVAL_SET_STRING(tv,hptr) do { \
735 (tv)->t = DUK_TAG_STRING; \
736 (tv)->v.hstring = (hptr); \
737 } while (0)
738
739#define DUK_TVAL_SET_OBJECT(tv,hptr) do { \
740 (tv)->t = DUK_TAG_OBJECT; \
741 (tv)->v.hobject = (hptr); \
742 } while (0)
743
744#define DUK_TVAL_SET_BUFFER(tv,hptr) do { \
745 (tv)->t = DUK_TAG_BUFFER; \
746 (tv)->v.hbuffer = (hptr); \
747 } while (0)
748
749#define DUK_TVAL_SET_NAN(tv) do { \
750 /* in non-packed representation we don't care about which NaN is used */ \
751 (tv)->t = DUK__TAG_NUMBER; \
752 (tv)->v.d = DUK_DOUBLE_NAN; \
753 } while (0)
754
755#define DUK_TVAL_SET_TVAL(v,x) do { *(v) = *(x); } while (0)
756
757/* getters */
758#define DUK_TVAL_GET_BOOLEAN(tv) ((tv)->v.i)
759#if defined(DUK_USE_FASTINT)
760#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->v.d)
761#define DUK_TVAL_GET_FASTINT(tv) ((tv)->v.fi)
762#define DUK_TVAL_GET_FASTINT_U32(tv) ((duk_uint32_t) ((tv)->v.fi))
763#define DUK_TVAL_GET_FASTINT_I32(tv) ((duk_int32_t) ((tv)->v.fi))
764#if 0
765#define DUK_TVAL_GET_NUMBER(tv) (DUK_TVAL_IS_FASTINT((tv)) ? \
766 (duk_double_t) DUK_TVAL_GET_FASTINT((tv)) : \
767 DUK_TVAL_GET_DOUBLE((tv)))
768#define DUK_TVAL_GET_NUMBER(tv) duk_tval_get_number_unpacked((tv))
769#else
770/* This seems reasonable overall. */
771#define DUK_TVAL_GET_NUMBER(tv) (DUK_TVAL_IS_FASTINT((tv)) ? \
772 duk_tval_get_number_unpacked_fastint((tv)) : \
773 DUK_TVAL_GET_DOUBLE((tv)))
774#endif
775#else
776#define DUK_TVAL_GET_NUMBER(tv) ((tv)->v.d)
777#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->v.d)
778#endif /* DUK_USE_FASTINT */
779#define DUK_TVAL_GET_POINTER(tv) ((tv)->v.voidptr)
780#define DUK_TVAL_GET_LIGHTFUNC(tv,out_fp,out_flags) do { \
781 (out_flags) = (duk_uint32_t) (tv)->v_extra; \
782 (out_fp) = (tv)->v.lightfunc; \
783 } while (0)
784#define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv) ((tv)->v.lightfunc)
785#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) ((duk_uint32_t) ((tv)->v_extra))
786#define DUK_TVAL_GET_STRING(tv) ((tv)->v.hstring)
787#define DUK_TVAL_GET_OBJECT(tv) ((tv)->v.hobject)
788#define DUK_TVAL_GET_BUFFER(tv) ((tv)->v.hbuffer)
789#define DUK_TVAL_GET_HEAPHDR(tv) ((tv)->v.heaphdr)
790
791/* decoding */
792#define DUK_TVAL_GET_TAG(tv) ((tv)->t)
793#define DUK_TVAL_IS_UNDEFINED(tv) ((tv)->t == DUK_TAG_UNDEFINED)
794#define DUK_TVAL_IS_UNUSED(tv) ((tv)->t == DUK_TAG_UNUSED)
795#define DUK_TVAL_IS_NULL(tv) ((tv)->t == DUK_TAG_NULL)
796#define DUK_TVAL_IS_BOOLEAN(tv) ((tv)->t == DUK_TAG_BOOLEAN)
797#define DUK_TVAL_IS_BOOLEAN_TRUE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i != 0))
798#define DUK_TVAL_IS_BOOLEAN_FALSE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i == 0))
799#if defined(DUK_USE_FASTINT)
800#define DUK_TVAL_IS_DOUBLE(tv) ((tv)->t == DUK__TAG_NUMBER)
801#define DUK_TVAL_IS_FASTINT(tv) ((tv)->t == DUK_TAG_FASTINT)
802#define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK__TAG_NUMBER || \
803 (tv)->t == DUK_TAG_FASTINT)
804#else
805#define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK__TAG_NUMBER)
806#define DUK_TVAL_IS_DOUBLE(v) DUK_TVAL_IS_NUMBER((v))
807#endif /* DUK_USE_FASTINT */
808#define DUK_TVAL_IS_POINTER(tv) ((tv)->t == DUK_TAG_POINTER)
809#define DUK_TVAL_IS_LIGHTFUNC(tv) ((tv)->t == DUK_TAG_LIGHTFUNC)
810#define DUK_TVAL_IS_STRING(tv) ((tv)->t == DUK_TAG_STRING)
811#define DUK_TVAL_IS_OBJECT(tv) ((tv)->t == DUK_TAG_OBJECT)
812#define DUK_TVAL_IS_BUFFER(tv) ((tv)->t == DUK_TAG_BUFFER)
813
814/* This is performance critical because it's needed for every DECREF.
815 * Take advantage of the fact that the first heap allocated tag is 8,
816 * so that bit 3 is set for all heap allocated tags (and never set for
817 * non-heap-allocated tags).
818 */
819#if 0
820#define DUK_TVAL_IS_HEAP_ALLOCATED(tv) ((tv)->t >= DUK_TAG_STRING)
821#endif
822#define DUK_TVAL_IS_HEAP_ALLOCATED(tv) ((tv)->t & 0x08)
823
824#if defined(DUK_USE_FASTINT)
825#if 0
826DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked(duk_tval *tv);
827#endif
828DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv);
829#endif
830
831#endif /* DUK_USE_PACKED_TVAL */
832
833/*
834 * Convenience (independent of representation)
835 */
836
837#define DUK_TVAL_SET_BOOLEAN_TRUE(v) DUK_TVAL_SET_BOOLEAN(v, 1)
838#define DUK_TVAL_SET_BOOLEAN_FALSE(v) DUK_TVAL_SET_BOOLEAN(v, 0)
839
840/* Lightfunc flags packing and unpacking. */
841/* Sign extend: 0x0000##00 -> 0x##000000 -> sign extend to 0xssssss## */
842#define DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags) \
843 ((((duk_int32_t) (lf_flags)) << 16) >> 24)
844#define DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags) \
845 (((lf_flags) >> 4) & 0x0f)
846#define DUK_LFUNC_FLAGS_GET_NARGS(lf_flags) \
847 ((lf_flags) & 0x0f)
848#define DUK_LFUNC_FLAGS_PACK(magic,length,nargs) \
849 (((magic) & 0xff) << 8) | ((length) << 4) | (nargs)
850
851#define DUK_LFUNC_NARGS_VARARGS 0x0f /* varargs marker */
852#define DUK_LFUNC_NARGS_MIN 0x00
853#define DUK_LFUNC_NARGS_MAX 0x0e /* max, excl. varargs marker */
854#define DUK_LFUNC_LENGTH_MIN 0x00
855#define DUK_LFUNC_LENGTH_MAX 0x0f
856#define DUK_LFUNC_MAGIC_MIN (-0x80)
857#define DUK_LFUNC_MAGIC_MAX 0x7f
858
859/* fastint constants etc */
860#if defined(DUK_USE_FASTINT)
861#define DUK_FASTINT_MIN (-0x800000000000LL)
862#define DUK_FASTINT_MAX 0x7fffffffffffLL
863#define DUK_FASTINT_BITS 48
864
865DUK_INTERNAL_DECL void duk_tval_set_number_chkfast(duk_tval *tv, duk_double_t x);
866#endif
867
868#endif /* DUK_TVAL_H_INCLUDED */
869/*
870 * Automatically generated by genbuiltins.py, do not edit!
871 */
872
873#ifndef DUK_BUILTINS_H_INCLUDED
874#define DUK_BUILTINS_H_INCLUDED
875
876#if defined(DUK_USE_ROM_STRINGS)
877#error ROM support not enabled, rerun make_dist.py with --rom-support
878#else /* DUK_USE_ROM_STRINGS */
879#define DUK_STRIDX_UC_UNDEFINED 0 /* 'Undefined' */
880#define DUK_HEAP_STRING_UC_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_UNDEFINED)
881#define DUK_HTHREAD_STRING_UC_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_UNDEFINED)
882#define DUK_STRIDX_UC_NULL 1 /* 'Null' */
883#define DUK_HEAP_STRING_UC_NULL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NULL)
884#define DUK_HTHREAD_STRING_UC_NULL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NULL)
885#define DUK_STRIDX_UC_ARGUMENTS 2 /* 'Arguments' */
886#define DUK_HEAP_STRING_UC_ARGUMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ARGUMENTS)
887#define DUK_HTHREAD_STRING_UC_ARGUMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ARGUMENTS)
888#define DUK_STRIDX_UC_OBJECT 3 /* 'Object' */
889#define DUK_HEAP_STRING_UC_OBJECT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_OBJECT)
890#define DUK_HTHREAD_STRING_UC_OBJECT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_OBJECT)
891#define DUK_STRIDX_UC_FUNCTION 4 /* 'Function' */
892#define DUK_HEAP_STRING_UC_FUNCTION(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_FUNCTION)
893#define DUK_HTHREAD_STRING_UC_FUNCTION(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_FUNCTION)
894#define DUK_STRIDX_ARRAY 5 /* 'Array' */
895#define DUK_HEAP_STRING_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ARRAY)
896#define DUK_HTHREAD_STRING_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ARRAY)
897#define DUK_STRIDX_UC_STRING 6 /* 'String' */
898#define DUK_HEAP_STRING_UC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_STRING)
899#define DUK_HTHREAD_STRING_UC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_STRING)
900#define DUK_STRIDX_UC_BOOLEAN 7 /* 'Boolean' */
901#define DUK_HEAP_STRING_UC_BOOLEAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BOOLEAN)
902#define DUK_HTHREAD_STRING_UC_BOOLEAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BOOLEAN)
903#define DUK_STRIDX_UC_NUMBER 8 /* 'Number' */
904#define DUK_HEAP_STRING_UC_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NUMBER)
905#define DUK_HTHREAD_STRING_UC_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NUMBER)
906#define DUK_STRIDX_DATE 9 /* 'Date' */
907#define DUK_HEAP_STRING_DATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATE)
908#define DUK_HTHREAD_STRING_DATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATE)
909#define DUK_STRIDX_REG_EXP 10 /* 'RegExp' */
910#define DUK_HEAP_STRING_REG_EXP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REG_EXP)
911#define DUK_HTHREAD_STRING_REG_EXP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REG_EXP)
912#define DUK_STRIDX_UC_ERROR 11 /* 'Error' */
913#define DUK_HEAP_STRING_UC_ERROR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ERROR)
914#define DUK_HTHREAD_STRING_UC_ERROR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ERROR)
915#define DUK_STRIDX_MATH 12 /* 'Math' */
916#define DUK_HEAP_STRING_MATH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MATH)
917#define DUK_HTHREAD_STRING_MATH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MATH)
918#define DUK_STRIDX_JSON 13 /* 'JSON' */
919#define DUK_HEAP_STRING_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON)
920#define DUK_HTHREAD_STRING_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON)
921#define DUK_STRIDX_EMPTY_STRING 14 /* '' */
922#define DUK_HEAP_STRING_EMPTY_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EMPTY_STRING)
923#define DUK_HTHREAD_STRING_EMPTY_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EMPTY_STRING)
924#define DUK_STRIDX_ARRAY_BUFFER 15 /* 'ArrayBuffer' */
925#define DUK_HEAP_STRING_ARRAY_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ARRAY_BUFFER)
926#define DUK_HTHREAD_STRING_ARRAY_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ARRAY_BUFFER)
927#define DUK_STRIDX_DATA_VIEW 16 /* 'DataView' */
928#define DUK_HEAP_STRING_DATA_VIEW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA_VIEW)
929#define DUK_HTHREAD_STRING_DATA_VIEW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA_VIEW)
930#define DUK_STRIDX_INT8_ARRAY 17 /* 'Int8Array' */
931#define DUK_HEAP_STRING_INT8_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT8_ARRAY)
932#define DUK_HTHREAD_STRING_INT8_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT8_ARRAY)
933#define DUK_STRIDX_UINT8_ARRAY 18 /* 'Uint8Array' */
934#define DUK_HEAP_STRING_UINT8_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT8_ARRAY)
935#define DUK_HTHREAD_STRING_UINT8_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT8_ARRAY)
936#define DUK_STRIDX_UINT8_CLAMPED_ARRAY 19 /* 'Uint8ClampedArray' */
937#define DUK_HEAP_STRING_UINT8_CLAMPED_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT8_CLAMPED_ARRAY)
938#define DUK_HTHREAD_STRING_UINT8_CLAMPED_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT8_CLAMPED_ARRAY)
939#define DUK_STRIDX_INT16_ARRAY 20 /* 'Int16Array' */
940#define DUK_HEAP_STRING_INT16_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT16_ARRAY)
941#define DUK_HTHREAD_STRING_INT16_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT16_ARRAY)
942#define DUK_STRIDX_UINT16_ARRAY 21 /* 'Uint16Array' */
943#define DUK_HEAP_STRING_UINT16_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT16_ARRAY)
944#define DUK_HTHREAD_STRING_UINT16_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT16_ARRAY)
945#define DUK_STRIDX_INT32_ARRAY 22 /* 'Int32Array' */
946#define DUK_HEAP_STRING_INT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT32_ARRAY)
947#define DUK_HTHREAD_STRING_INT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT32_ARRAY)
948#define DUK_STRIDX_UINT32_ARRAY 23 /* 'Uint32Array' */
949#define DUK_HEAP_STRING_UINT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT32_ARRAY)
950#define DUK_HTHREAD_STRING_UINT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT32_ARRAY)
951#define DUK_STRIDX_FLOAT32_ARRAY 24 /* 'Float32Array' */
952#define DUK_HEAP_STRING_FLOAT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOAT32_ARRAY)
953#define DUK_HTHREAD_STRING_FLOAT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOAT32_ARRAY)
954#define DUK_STRIDX_FLOAT64_ARRAY 25 /* 'Float64Array' */
955#define DUK_HEAP_STRING_FLOAT64_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOAT64_ARRAY)
956#define DUK_HTHREAD_STRING_FLOAT64_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOAT64_ARRAY)
957#define DUK_STRIDX_GLOBAL 26 /* 'global' */
958#define DUK_HEAP_STRING_GLOBAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GLOBAL)
959#define DUK_HTHREAD_STRING_GLOBAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GLOBAL)
960#define DUK_STRIDX_OBJ_ENV 27 /* 'ObjEnv' */
961#define DUK_HEAP_STRING_OBJ_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OBJ_ENV)
962#define DUK_HTHREAD_STRING_OBJ_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OBJ_ENV)
963#define DUK_STRIDX_DEC_ENV 28 /* 'DecEnv' */
964#define DUK_HEAP_STRING_DEC_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEC_ENV)
965#define DUK_HTHREAD_STRING_DEC_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEC_ENV)
966#define DUK_STRIDX_UC_BUFFER 29 /* 'Buffer' */
967#define DUK_HEAP_STRING_UC_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BUFFER)
968#define DUK_HTHREAD_STRING_UC_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BUFFER)
969#define DUK_STRIDX_UC_POINTER 30 /* 'Pointer' */
970#define DUK_HEAP_STRING_UC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_POINTER)
971#define DUK_HTHREAD_STRING_UC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_POINTER)
972#define DUK_STRIDX_UC_THREAD 31 /* 'Thread' */
973#define DUK_HEAP_STRING_UC_THREAD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_THREAD)
974#define DUK_HTHREAD_STRING_UC_THREAD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_THREAD)
975#define DUK_STRIDX_EVAL 32 /* 'eval' */
976#define DUK_HEAP_STRING_EVAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EVAL)
977#define DUK_HTHREAD_STRING_EVAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EVAL)
978#define DUK_STRIDX_DEFINE_PROPERTY 33 /* 'defineProperty' */
979#define DUK_HEAP_STRING_DEFINE_PROPERTY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFINE_PROPERTY)
980#define DUK_HTHREAD_STRING_DEFINE_PROPERTY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFINE_PROPERTY)
981#define DUK_STRIDX_VALUE 34 /* 'value' */
982#define DUK_HEAP_STRING_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE)
983#define DUK_HTHREAD_STRING_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE)
984#define DUK_STRIDX_WRITABLE 35 /* 'writable' */
985#define DUK_HEAP_STRING_WRITABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WRITABLE)
986#define DUK_HTHREAD_STRING_WRITABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WRITABLE)
987#define DUK_STRIDX_CONFIGURABLE 36 /* 'configurable' */
988#define DUK_HEAP_STRING_CONFIGURABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONFIGURABLE)
989#define DUK_HTHREAD_STRING_CONFIGURABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONFIGURABLE)
990#define DUK_STRIDX_ENUMERABLE 37 /* 'enumerable' */
991#define DUK_HEAP_STRING_ENUMERABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUMERABLE)
992#define DUK_HTHREAD_STRING_ENUMERABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUMERABLE)
993#define DUK_STRIDX_JOIN 38 /* 'join' */
994#define DUK_HEAP_STRING_JOIN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JOIN)
995#define DUK_HTHREAD_STRING_JOIN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JOIN)
996#define DUK_STRIDX_TO_LOCALE_STRING 39 /* 'toLocaleString' */
997#define DUK_HEAP_STRING_TO_LOCALE_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOCALE_STRING)
998#define DUK_HTHREAD_STRING_TO_LOCALE_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOCALE_STRING)
999#define DUK_STRIDX_VALUE_OF 40 /* 'valueOf' */
1000#define DUK_HEAP_STRING_VALUE_OF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE_OF)
1001#define DUK_HTHREAD_STRING_VALUE_OF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE_OF)
1002#define DUK_STRIDX_TO_UTC_STRING 41 /* 'toUTCString' */
1003#define DUK_HEAP_STRING_TO_UTC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_UTC_STRING)
1004#define DUK_HTHREAD_STRING_TO_UTC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_UTC_STRING)
1005#define DUK_STRIDX_TO_ISO_STRING 42 /* 'toISOString' */
1006#define DUK_HEAP_STRING_TO_ISO_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_ISO_STRING)
1007#define DUK_HTHREAD_STRING_TO_ISO_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_ISO_STRING)
1008#define DUK_STRIDX_TO_GMT_STRING 43 /* 'toGMTString' */
1009#define DUK_HEAP_STRING_TO_GMT_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_GMT_STRING)
1010#define DUK_HTHREAD_STRING_TO_GMT_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_GMT_STRING)
1011#define DUK_STRIDX_SOURCE 44 /* 'source' */
1012#define DUK_HEAP_STRING_SOURCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SOURCE)
1013#define DUK_HTHREAD_STRING_SOURCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SOURCE)
1014#define DUK_STRIDX_IGNORE_CASE 45 /* 'ignoreCase' */
1015#define DUK_HEAP_STRING_IGNORE_CASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IGNORE_CASE)
1016#define DUK_HTHREAD_STRING_IGNORE_CASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IGNORE_CASE)
1017#define DUK_STRIDX_MULTILINE 46 /* 'multiline' */
1018#define DUK_HEAP_STRING_MULTILINE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MULTILINE)
1019#define DUK_HTHREAD_STRING_MULTILINE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MULTILINE)
1020#define DUK_STRIDX_LAST_INDEX 47 /* 'lastIndex' */
1021#define DUK_HEAP_STRING_LAST_INDEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LAST_INDEX)
1022#define DUK_HTHREAD_STRING_LAST_INDEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LAST_INDEX)
1023#define DUK_STRIDX_ESCAPED_EMPTY_REGEXP 48 /* '(?:)' */
1024#define DUK_HEAP_STRING_ESCAPED_EMPTY_REGEXP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ESCAPED_EMPTY_REGEXP)
1025#define DUK_HTHREAD_STRING_ESCAPED_EMPTY_REGEXP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ESCAPED_EMPTY_REGEXP)
1026#define DUK_STRIDX_INDEX 49 /* 'index' */
1027#define DUK_HEAP_STRING_INDEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INDEX)
1028#define DUK_HTHREAD_STRING_INDEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INDEX)
1029#define DUK_STRIDX_PROTOTYPE 50 /* 'prototype' */
1030#define DUK_HEAP_STRING_PROTOTYPE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTOTYPE)
1031#define DUK_HTHREAD_STRING_PROTOTYPE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTOTYPE)
1032#define DUK_STRIDX_CONSTRUCTOR 51 /* 'constructor' */
1033#define DUK_HEAP_STRING_CONSTRUCTOR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONSTRUCTOR)
1034#define DUK_HTHREAD_STRING_CONSTRUCTOR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONSTRUCTOR)
1035#define DUK_STRIDX_MESSAGE 52 /* 'message' */
1036#define DUK_HEAP_STRING_MESSAGE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MESSAGE)
1037#define DUK_HTHREAD_STRING_MESSAGE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MESSAGE)
1038#define DUK_STRIDX_LC_BOOLEAN 53 /* 'boolean' */
7c673cae
FG
1039#define DUK_HEAP_STRING_LC_BOOLEAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_BOOLEAN)
1040#define DUK_HTHREAD_STRING_LC_BOOLEAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_BOOLEAN)
11fdf7f2
TL
1041#define DUK_STRIDX_LC_NUMBER 54 /* 'number' */
1042#define DUK_HEAP_STRING_LC_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NUMBER)
1043#define DUK_HTHREAD_STRING_LC_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NUMBER)
1044#define DUK_STRIDX_LC_STRING 55 /* 'string' */
1045#define DUK_HEAP_STRING_LC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_STRING)
1046#define DUK_HTHREAD_STRING_LC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_STRING)
1047#define DUK_STRIDX_LC_OBJECT 56 /* 'object' */
1048#define DUK_HEAP_STRING_LC_OBJECT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_OBJECT)
1049#define DUK_HTHREAD_STRING_LC_OBJECT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_OBJECT)
1050#define DUK_STRIDX_LC_UNDEFINED 57 /* 'undefined' */
7c673cae
FG
1051#define DUK_HEAP_STRING_LC_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_UNDEFINED)
1052#define DUK_HTHREAD_STRING_LC_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_UNDEFINED)
11fdf7f2 1053#define DUK_STRIDX_NAN 58 /* 'NaN' */
7c673cae
FG
1054#define DUK_HEAP_STRING_NAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAN)
1055#define DUK_HTHREAD_STRING_NAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAN)
11fdf7f2
TL
1056#define DUK_STRIDX_INFINITY 59 /* 'Infinity' */
1057#define DUK_HEAP_STRING_INFINITY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INFINITY)
1058#define DUK_HTHREAD_STRING_INFINITY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INFINITY)
1059#define DUK_STRIDX_MINUS_INFINITY 60 /* '-Infinity' */
1060#define DUK_HEAP_STRING_MINUS_INFINITY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_INFINITY)
1061#define DUK_HTHREAD_STRING_MINUS_INFINITY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_INFINITY)
1062#define DUK_STRIDX_MINUS_ZERO 61 /* '-0' */
1063#define DUK_HEAP_STRING_MINUS_ZERO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_ZERO)
1064#define DUK_HTHREAD_STRING_MINUS_ZERO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_ZERO)
1065#define DUK_STRIDX_COMMA 62 /* ',' */
1066#define DUK_HEAP_STRING_COMMA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMMA)
1067#define DUK_HTHREAD_STRING_COMMA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMMA)
1068#define DUK_STRIDX_SPACE 63 /* ' ' */
1069#define DUK_HEAP_STRING_SPACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SPACE)
1070#define DUK_HTHREAD_STRING_SPACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SPACE)
1071#define DUK_STRIDX_NEWLINE_4SPACE 64 /* '\n ' */
1072#define DUK_HEAP_STRING_NEWLINE_4SPACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEWLINE_4SPACE)
1073#define DUK_HTHREAD_STRING_NEWLINE_4SPACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEWLINE_4SPACE)
1074#define DUK_STRIDX_BRACKETED_ELLIPSIS 65 /* '[...]' */
1075#define DUK_HEAP_STRING_BRACKETED_ELLIPSIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BRACKETED_ELLIPSIS)
1076#define DUK_HTHREAD_STRING_BRACKETED_ELLIPSIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BRACKETED_ELLIPSIS)
1077#define DUK_STRIDX_INVALID_DATE 66 /* 'Invalid Date' */
1078#define DUK_HEAP_STRING_INVALID_DATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INVALID_DATE)
1079#define DUK_HTHREAD_STRING_INVALID_DATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INVALID_DATE)
1080#define DUK_STRIDX_LC_ARGUMENTS 67 /* 'arguments' */
7c673cae
FG
1081#define DUK_HEAP_STRING_LC_ARGUMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_ARGUMENTS)
1082#define DUK_HTHREAD_STRING_LC_ARGUMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_ARGUMENTS)
11fdf7f2
TL
1083#define DUK_STRIDX_CALLEE 68 /* 'callee' */
1084#define DUK_HEAP_STRING_CALLEE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLEE)
1085#define DUK_HTHREAD_STRING_CALLEE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLEE)
1086#define DUK_STRIDX_CALLER 69 /* 'caller' */
7c673cae
FG
1087#define DUK_HEAP_STRING_CALLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLER)
1088#define DUK_HTHREAD_STRING_CALLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLER)
11fdf7f2
TL
1089#define DUK_STRIDX_HAS 70 /* 'has' */
1090#define DUK_HEAP_STRING_HAS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HAS)
1091#define DUK_HTHREAD_STRING_HAS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HAS)
1092#define DUK_STRIDX_GET 71 /* 'get' */
7c673cae
FG
1093#define DUK_HEAP_STRING_GET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET)
1094#define DUK_HTHREAD_STRING_GET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET)
11fdf7f2
TL
1095#define DUK_STRIDX_DELETE_PROPERTY 72 /* 'deleteProperty' */
1096#define DUK_HEAP_STRING_DELETE_PROPERTY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE_PROPERTY)
1097#define DUK_HTHREAD_STRING_DELETE_PROPERTY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE_PROPERTY)
1098#define DUK_STRIDX_ENUMERATE 73 /* 'enumerate' */
1099#define DUK_HEAP_STRING_ENUMERATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUMERATE)
1100#define DUK_HTHREAD_STRING_ENUMERATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUMERATE)
1101#define DUK_STRIDX_OWN_KEYS 74 /* 'ownKeys' */
1102#define DUK_HEAP_STRING_OWN_KEYS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OWN_KEYS)
1103#define DUK_HTHREAD_STRING_OWN_KEYS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OWN_KEYS)
1104#define DUK_STRIDX_SET_PROTOTYPE_OF 75 /* 'setPrototypeOf' */
1105#define DUK_HEAP_STRING_SET_PROTOTYPE_OF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_PROTOTYPE_OF)
1106#define DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_PROTOTYPE_OF)
1107#define DUK_STRIDX___PROTO__ 76 /* '__proto__' */
1108#define DUK_HEAP_STRING___PROTO__(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX___PROTO__)
1109#define DUK_HTHREAD_STRING___PROTO__(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX___PROTO__)
1110#define DUK_STRIDX_REQUIRE 77 /* 'require' */
1111#define DUK_HEAP_STRING_REQUIRE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REQUIRE)
1112#define DUK_HTHREAD_STRING_REQUIRE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REQUIRE)
1113#define DUK_STRIDX_ID 78 /* 'id' */
1114#define DUK_HEAP_STRING_ID(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ID)
1115#define DUK_HTHREAD_STRING_ID(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ID)
1116#define DUK_STRIDX_EXPORTS 79 /* 'exports' */
1117#define DUK_HEAP_STRING_EXPORTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORTS)
1118#define DUK_HTHREAD_STRING_EXPORTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXPORTS)
1119#define DUK_STRIDX_FILENAME 80 /* 'filename' */
1120#define DUK_HEAP_STRING_FILENAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILENAME)
1121#define DUK_HTHREAD_STRING_FILENAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILENAME)
1122#define DUK_STRIDX_TO_STRING 81 /* 'toString' */
1123#define DUK_HEAP_STRING_TO_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_STRING)
1124#define DUK_HTHREAD_STRING_TO_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_STRING)
1125#define DUK_STRIDX_TO_JSON 82 /* 'toJSON' */
1126#define DUK_HEAP_STRING_TO_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_JSON)
1127#define DUK_HTHREAD_STRING_TO_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_JSON)
1128#define DUK_STRIDX_TYPE 83 /* 'type' */
1129#define DUK_HEAP_STRING_TYPE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPE)
1130#define DUK_HTHREAD_STRING_TYPE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPE)
1131#define DUK_STRIDX_DATA 84 /* 'data' */
1132#define DUK_HEAP_STRING_DATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA)
1133#define DUK_HTHREAD_STRING_DATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA)
1134#define DUK_STRIDX_LENGTH 85 /* 'length' */
7c673cae
FG
1135#define DUK_HEAP_STRING_LENGTH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LENGTH)
1136#define DUK_HTHREAD_STRING_LENGTH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LENGTH)
11fdf7f2
TL
1137#define DUK_STRIDX_BYTE_LENGTH 86 /* 'byteLength' */
1138#define DUK_HEAP_STRING_BYTE_LENGTH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BYTE_LENGTH)
1139#define DUK_HTHREAD_STRING_BYTE_LENGTH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BYTE_LENGTH)
1140#define DUK_STRIDX_BYTE_OFFSET 87 /* 'byteOffset' */
1141#define DUK_HEAP_STRING_BYTE_OFFSET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BYTE_OFFSET)
1142#define DUK_HTHREAD_STRING_BYTE_OFFSET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BYTE_OFFSET)
1143#define DUK_STRIDX_BYTES_PER_ELEMENT 88 /* 'BYTES_PER_ELEMENT' */
1144#define DUK_HEAP_STRING_BYTES_PER_ELEMENT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BYTES_PER_ELEMENT)
1145#define DUK_HTHREAD_STRING_BYTES_PER_ELEMENT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BYTES_PER_ELEMENT)
1146#define DUK_STRIDX_SET 89 /* 'set' */
1147#define DUK_HEAP_STRING_SET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET)
1148#define DUK_HTHREAD_STRING_SET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET)
1149#define DUK_STRIDX_STACK 90 /* 'stack' */
1150#define DUK_HEAP_STRING_STACK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STACK)
1151#define DUK_HTHREAD_STRING_STACK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STACK)
1152#define DUK_STRIDX_PC 91 /* 'pc' */
1153#define DUK_HEAP_STRING_PC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PC)
1154#define DUK_HTHREAD_STRING_PC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PC)
1155#define DUK_STRIDX_LINE_NUMBER 92 /* 'lineNumber' */
1156#define DUK_HEAP_STRING_LINE_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LINE_NUMBER)
1157#define DUK_HTHREAD_STRING_LINE_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LINE_NUMBER)
1158#define DUK_STRIDX_INT_TRACEDATA 93 /* '\xffTracedata' */
1159#define DUK_HEAP_STRING_INT_TRACEDATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TRACEDATA)
1160#define DUK_HTHREAD_STRING_INT_TRACEDATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TRACEDATA)
1161#define DUK_STRIDX_NAME 94 /* 'name' */
1162#define DUK_HEAP_STRING_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAME)
1163#define DUK_HTHREAD_STRING_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAME)
1164#define DUK_STRIDX_FILE_NAME 95 /* 'fileName' */
1165#define DUK_HEAP_STRING_FILE_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILE_NAME)
1166#define DUK_HTHREAD_STRING_FILE_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILE_NAME)
1167#define DUK_STRIDX_LC_BUFFER 96 /* 'buffer' */
1168#define DUK_HEAP_STRING_LC_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_BUFFER)
1169#define DUK_HTHREAD_STRING_LC_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_BUFFER)
1170#define DUK_STRIDX_LC_POINTER 97 /* 'pointer' */
1171#define DUK_HEAP_STRING_LC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_POINTER)
1172#define DUK_HTHREAD_STRING_LC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_POINTER)
1173#define DUK_STRIDX_INT_VALUE 98 /* '\xffValue' */
1174#define DUK_HEAP_STRING_INT_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VALUE)
1175#define DUK_HTHREAD_STRING_INT_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VALUE)
1176#define DUK_STRIDX_INT_NEXT 99 /* '\xffNext' */
1177#define DUK_HEAP_STRING_INT_NEXT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_NEXT)
1178#define DUK_HTHREAD_STRING_INT_NEXT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_NEXT)
1179#define DUK_STRIDX_INT_BYTECODE 100 /* '\xffBytecode' */
1180#define DUK_HEAP_STRING_INT_BYTECODE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_BYTECODE)
1181#define DUK_HTHREAD_STRING_INT_BYTECODE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_BYTECODE)
1182#define DUK_STRIDX_INT_FORMALS 101 /* '\xffFormals' */
1183#define DUK_HEAP_STRING_INT_FORMALS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FORMALS)
1184#define DUK_HTHREAD_STRING_INT_FORMALS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FORMALS)
1185#define DUK_STRIDX_INT_VARMAP 102 /* '\xffVarmap' */
1186#define DUK_HEAP_STRING_INT_VARMAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARMAP)
1187#define DUK_HTHREAD_STRING_INT_VARMAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARMAP)
1188#define DUK_STRIDX_INT_LEXENV 103 /* '\xffLexenv' */
1189#define DUK_HEAP_STRING_INT_LEXENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_LEXENV)
1190#define DUK_HTHREAD_STRING_INT_LEXENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_LEXENV)
1191#define DUK_STRIDX_INT_VARENV 104 /* '\xffVarenv' */
1192#define DUK_HEAP_STRING_INT_VARENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARENV)
1193#define DUK_HTHREAD_STRING_INT_VARENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARENV)
1194#define DUK_STRIDX_INT_SOURCE 105 /* '\xffSource' */
1195#define DUK_HEAP_STRING_INT_SOURCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_SOURCE)
1196#define DUK_HTHREAD_STRING_INT_SOURCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_SOURCE)
1197#define DUK_STRIDX_INT_PC2LINE 106 /* '\xffPc2line' */
1198#define DUK_HEAP_STRING_INT_PC2LINE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_PC2LINE)
1199#define DUK_HTHREAD_STRING_INT_PC2LINE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_PC2LINE)
1200#define DUK_STRIDX_INT_ARGS 107 /* '\xffArgs' */
1201#define DUK_HEAP_STRING_INT_ARGS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_ARGS)
1202#define DUK_HTHREAD_STRING_INT_ARGS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_ARGS)
1203#define DUK_STRIDX_INT_MAP 108 /* '\xffMap' */
1204#define DUK_HEAP_STRING_INT_MAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_MAP)
1205#define DUK_HTHREAD_STRING_INT_MAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_MAP)
1206#define DUK_STRIDX_INT_FINALIZER 109 /* '\xffFinalizer' */
1207#define DUK_HEAP_STRING_INT_FINALIZER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FINALIZER)
1208#define DUK_HTHREAD_STRING_INT_FINALIZER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FINALIZER)
1209#define DUK_STRIDX_INT_HANDLER 110 /* '\xffHandler' */
1210#define DUK_HEAP_STRING_INT_HANDLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_HANDLER)
1211#define DUK_HTHREAD_STRING_INT_HANDLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_HANDLER)
1212#define DUK_STRIDX_INT_CALLEE 111 /* '\xffCallee' */
1213#define DUK_HEAP_STRING_INT_CALLEE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_CALLEE)
1214#define DUK_HTHREAD_STRING_INT_CALLEE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_CALLEE)
1215#define DUK_STRIDX_INT_THREAD 112 /* '\xffThread' */
1216#define DUK_HEAP_STRING_INT_THREAD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THREAD)
1217#define DUK_HTHREAD_STRING_INT_THREAD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THREAD)
1218#define DUK_STRIDX_INT_REGBASE 113 /* '\xffRegbase' */
1219#define DUK_HEAP_STRING_INT_REGBASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_REGBASE)
1220#define DUK_HTHREAD_STRING_INT_REGBASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_REGBASE)
1221#define DUK_STRIDX_INT_TARGET 114 /* '\xffTarget' */
1222#define DUK_HEAP_STRING_INT_TARGET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TARGET)
1223#define DUK_HTHREAD_STRING_INT_TARGET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TARGET)
1224#define DUK_STRIDX_INT_THIS 115 /* '\xffThis' */
1225#define DUK_HEAP_STRING_INT_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THIS)
1226#define DUK_HTHREAD_STRING_INT_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THIS)
1227#define DUK_STRIDX_COMPILE 116 /* 'compile' */
1228#define DUK_HEAP_STRING_COMPILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMPILE)
1229#define DUK_HTHREAD_STRING_COMPILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMPILE)
1230#define DUK_STRIDX_INPUT 117 /* 'input' */
1231#define DUK_HEAP_STRING_INPUT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INPUT)
1232#define DUK_HTHREAD_STRING_INPUT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INPUT)
1233#define DUK_STRIDX_ERR_CREATE 118 /* 'errCreate' */
1234#define DUK_HEAP_STRING_ERR_CREATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_CREATE)
1235#define DUK_HTHREAD_STRING_ERR_CREATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_CREATE)
1236#define DUK_STRIDX_ERR_THROW 119 /* 'errThrow' */
1237#define DUK_HEAP_STRING_ERR_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_THROW)
1238#define DUK_HTHREAD_STRING_ERR_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_THROW)
1239#define DUK_STRIDX_MOD_SEARCH 120 /* 'modSearch' */
1240#define DUK_HEAP_STRING_MOD_SEARCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MOD_SEARCH)
1241#define DUK_HTHREAD_STRING_MOD_SEARCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MOD_SEARCH)
1242#define DUK_STRIDX_MOD_LOADED 121 /* 'modLoaded' */
1243#define DUK_HEAP_STRING_MOD_LOADED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MOD_LOADED)
1244#define DUK_HTHREAD_STRING_MOD_LOADED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MOD_LOADED)
1245#define DUK_STRIDX_ENV 122 /* 'env' */
1246#define DUK_HEAP_STRING_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENV)
1247#define DUK_HTHREAD_STRING_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENV)
1248#define DUK_STRIDX_HEX 123 /* 'hex' */
1249#define DUK_HEAP_STRING_HEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HEX)
1250#define DUK_HTHREAD_STRING_HEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HEX)
1251#define DUK_STRIDX_BASE64 124 /* 'base64' */
1252#define DUK_HEAP_STRING_BASE64(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BASE64)
1253#define DUK_HTHREAD_STRING_BASE64(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BASE64)
1254#define DUK_STRIDX_JX 125 /* 'jx' */
1255#define DUK_HEAP_STRING_JX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JX)
1256#define DUK_HTHREAD_STRING_JX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JX)
1257#define DUK_STRIDX_JC 126 /* 'jc' */
1258#define DUK_HEAP_STRING_JC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JC)
1259#define DUK_HTHREAD_STRING_JC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JC)
1260#define DUK_STRIDX_RESUME 127 /* 'resume' */
1261#define DUK_HEAP_STRING_RESUME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RESUME)
1262#define DUK_HTHREAD_STRING_RESUME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RESUME)
1263#define DUK_STRIDX_FMT 128 /* 'fmt' */
1264#define DUK_HEAP_STRING_FMT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FMT)
1265#define DUK_HTHREAD_STRING_FMT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FMT)
1266#define DUK_STRIDX_RAW 129 /* 'raw' */
1267#define DUK_HEAP_STRING_RAW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RAW)
1268#define DUK_HTHREAD_STRING_RAW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RAW)
1269#define DUK_STRIDX_LC_TRACE 130 /* 'trace' */
1270#define DUK_HEAP_STRING_LC_TRACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_TRACE)
1271#define DUK_HTHREAD_STRING_LC_TRACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_TRACE)
1272#define DUK_STRIDX_LC_DEBUG 131 /* 'debug' */
1273#define DUK_HEAP_STRING_LC_DEBUG(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_DEBUG)
1274#define DUK_HTHREAD_STRING_LC_DEBUG(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_DEBUG)
1275#define DUK_STRIDX_LC_INFO 132 /* 'info' */
1276#define DUK_HEAP_STRING_LC_INFO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_INFO)
1277#define DUK_HTHREAD_STRING_LC_INFO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_INFO)
1278#define DUK_STRIDX_LC_WARN 133 /* 'warn' */
1279#define DUK_HEAP_STRING_LC_WARN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_WARN)
1280#define DUK_HTHREAD_STRING_LC_WARN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_WARN)
1281#define DUK_STRIDX_LC_ERROR 134 /* 'error' */
1282#define DUK_HEAP_STRING_LC_ERROR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_ERROR)
1283#define DUK_HTHREAD_STRING_LC_ERROR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_ERROR)
1284#define DUK_STRIDX_LC_FATAL 135 /* 'fatal' */
1285#define DUK_HEAP_STRING_LC_FATAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FATAL)
1286#define DUK_HTHREAD_STRING_LC_FATAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FATAL)
1287#define DUK_STRIDX_LC_N 136 /* 'n' */
1288#define DUK_HEAP_STRING_LC_N(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_N)
1289#define DUK_HTHREAD_STRING_LC_N(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_N)
1290#define DUK_STRIDX_LC_L 137 /* 'l' */
1291#define DUK_HEAP_STRING_LC_L(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_L)
1292#define DUK_HTHREAD_STRING_LC_L(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_L)
1293#define DUK_STRIDX_CLOG 138 /* 'clog' */
1294#define DUK_HEAP_STRING_CLOG(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLOG)
1295#define DUK_HTHREAD_STRING_CLOG(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLOG)
1296#define DUK_STRIDX_TO_LOG_STRING 139 /* 'toLogString' */
1297#define DUK_HEAP_STRING_TO_LOG_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOG_STRING)
1298#define DUK_HTHREAD_STRING_TO_LOG_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOG_STRING)
1299#define DUK_STRIDX_JSON_EXT_UNDEFINED 140 /* '{"_undef":true}' */
1300#define DUK_HEAP_STRING_JSON_EXT_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_UNDEFINED)
1301#define DUK_HTHREAD_STRING_JSON_EXT_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_UNDEFINED)
1302#define DUK_STRIDX_JSON_EXT_NAN 141 /* '{"_nan":true}' */
1303#define DUK_HEAP_STRING_JSON_EXT_NAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NAN)
1304#define DUK_HTHREAD_STRING_JSON_EXT_NAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NAN)
1305#define DUK_STRIDX_JSON_EXT_POSINF 142 /* '{"_inf":true}' */
1306#define DUK_HEAP_STRING_JSON_EXT_POSINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_POSINF)
1307#define DUK_HTHREAD_STRING_JSON_EXT_POSINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_POSINF)
1308#define DUK_STRIDX_JSON_EXT_NEGINF 143 /* '{"_ninf":true}' */
1309#define DUK_HEAP_STRING_JSON_EXT_NEGINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NEGINF)
1310#define DUK_HTHREAD_STRING_JSON_EXT_NEGINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NEGINF)
1311#define DUK_STRIDX_JSON_EXT_FUNCTION1 144 /* '{"_func":true}' */
1312#define DUK_HEAP_STRING_JSON_EXT_FUNCTION1(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION1)
1313#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION1(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION1)
1314#define DUK_STRIDX_JSON_EXT_FUNCTION2 145 /* '{_func:true}' */
1315#define DUK_HEAP_STRING_JSON_EXT_FUNCTION2(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION2)
1316#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION2(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION2)
1317#define DUK_STRIDX_BREAK 146 /* 'break' */
7c673cae
FG
1318#define DUK_HEAP_STRING_BREAK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BREAK)
1319#define DUK_HTHREAD_STRING_BREAK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BREAK)
11fdf7f2 1320#define DUK_STRIDX_CASE 147 /* 'case' */
7c673cae
FG
1321#define DUK_HEAP_STRING_CASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CASE)
1322#define DUK_HTHREAD_STRING_CASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CASE)
11fdf7f2 1323#define DUK_STRIDX_CATCH 148 /* 'catch' */
7c673cae
FG
1324#define DUK_HEAP_STRING_CATCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CATCH)
1325#define DUK_HTHREAD_STRING_CATCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CATCH)
11fdf7f2 1326#define DUK_STRIDX_CONTINUE 149 /* 'continue' */
7c673cae
FG
1327#define DUK_HEAP_STRING_CONTINUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONTINUE)
1328#define DUK_HTHREAD_STRING_CONTINUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONTINUE)
11fdf7f2 1329#define DUK_STRIDX_DEBUGGER 150 /* 'debugger' */
7c673cae
FG
1330#define DUK_HEAP_STRING_DEBUGGER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEBUGGER)
1331#define DUK_HTHREAD_STRING_DEBUGGER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEBUGGER)
11fdf7f2 1332#define DUK_STRIDX_DEFAULT 151 /* 'default' */
7c673cae
FG
1333#define DUK_HEAP_STRING_DEFAULT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFAULT)
1334#define DUK_HTHREAD_STRING_DEFAULT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFAULT)
11fdf7f2 1335#define DUK_STRIDX_DELETE 152 /* 'delete' */
7c673cae
FG
1336#define DUK_HEAP_STRING_DELETE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE)
1337#define DUK_HTHREAD_STRING_DELETE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE)
11fdf7f2 1338#define DUK_STRIDX_DO 153 /* 'do' */
7c673cae
FG
1339#define DUK_HEAP_STRING_DO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DO)
1340#define DUK_HTHREAD_STRING_DO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DO)
11fdf7f2 1341#define DUK_STRIDX_ELSE 154 /* 'else' */
7c673cae
FG
1342#define DUK_HEAP_STRING_ELSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ELSE)
1343#define DUK_HTHREAD_STRING_ELSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ELSE)
11fdf7f2 1344#define DUK_STRIDX_FINALLY 155 /* 'finally' */
7c673cae
FG
1345#define DUK_HEAP_STRING_FINALLY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FINALLY)
1346#define DUK_HTHREAD_STRING_FINALLY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FINALLY)
11fdf7f2 1347#define DUK_STRIDX_FOR 156 /* 'for' */
7c673cae
FG
1348#define DUK_HEAP_STRING_FOR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FOR)
1349#define DUK_HTHREAD_STRING_FOR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FOR)
11fdf7f2 1350#define DUK_STRIDX_LC_FUNCTION 157 /* 'function' */
7c673cae
FG
1351#define DUK_HEAP_STRING_LC_FUNCTION(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FUNCTION)
1352#define DUK_HTHREAD_STRING_LC_FUNCTION(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FUNCTION)
11fdf7f2 1353#define DUK_STRIDX_IF 158 /* 'if' */
7c673cae
FG
1354#define DUK_HEAP_STRING_IF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IF)
1355#define DUK_HTHREAD_STRING_IF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IF)
11fdf7f2 1356#define DUK_STRIDX_IN 159 /* 'in' */
7c673cae
FG
1357#define DUK_HEAP_STRING_IN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IN)
1358#define DUK_HTHREAD_STRING_IN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IN)
11fdf7f2 1359#define DUK_STRIDX_INSTANCEOF 160 /* 'instanceof' */
7c673cae
FG
1360#define DUK_HEAP_STRING_INSTANCEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INSTANCEOF)
1361#define DUK_HTHREAD_STRING_INSTANCEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INSTANCEOF)
11fdf7f2 1362#define DUK_STRIDX_NEW 161 /* 'new' */
7c673cae
FG
1363#define DUK_HEAP_STRING_NEW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEW)
1364#define DUK_HTHREAD_STRING_NEW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEW)
11fdf7f2 1365#define DUK_STRIDX_RETURN 162 /* 'return' */
7c673cae
FG
1366#define DUK_HEAP_STRING_RETURN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RETURN)
1367#define DUK_HTHREAD_STRING_RETURN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RETURN)
11fdf7f2 1368#define DUK_STRIDX_SWITCH 163 /* 'switch' */
7c673cae
FG
1369#define DUK_HEAP_STRING_SWITCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SWITCH)
1370#define DUK_HTHREAD_STRING_SWITCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SWITCH)
11fdf7f2 1371#define DUK_STRIDX_THIS 164 /* 'this' */
7c673cae
FG
1372#define DUK_HEAP_STRING_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THIS)
1373#define DUK_HTHREAD_STRING_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THIS)
11fdf7f2 1374#define DUK_STRIDX_THROW 165 /* 'throw' */
7c673cae
FG
1375#define DUK_HEAP_STRING_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THROW)
1376#define DUK_HTHREAD_STRING_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THROW)
11fdf7f2 1377#define DUK_STRIDX_TRY 166 /* 'try' */
7c673cae
FG
1378#define DUK_HEAP_STRING_TRY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRY)
1379#define DUK_HTHREAD_STRING_TRY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRY)
11fdf7f2 1380#define DUK_STRIDX_TYPEOF 167 /* 'typeof' */
7c673cae
FG
1381#define DUK_HEAP_STRING_TYPEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPEOF)
1382#define DUK_HTHREAD_STRING_TYPEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPEOF)
11fdf7f2 1383#define DUK_STRIDX_VAR 168 /* 'var' */
7c673cae
FG
1384#define DUK_HEAP_STRING_VAR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VAR)
1385#define DUK_HTHREAD_STRING_VAR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VAR)
11fdf7f2
TL
1386#define DUK_STRIDX_CONST 169 /* 'const' */
1387#define DUK_HEAP_STRING_CONST(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST)
1388#define DUK_HTHREAD_STRING_CONST(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST)
1389#define DUK_STRIDX_VOID 170 /* 'void' */
7c673cae
FG
1390#define DUK_HEAP_STRING_VOID(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VOID)
1391#define DUK_HTHREAD_STRING_VOID(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VOID)
11fdf7f2 1392#define DUK_STRIDX_WHILE 171 /* 'while' */
7c673cae
FG
1393#define DUK_HEAP_STRING_WHILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WHILE)
1394#define DUK_HTHREAD_STRING_WHILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WHILE)
11fdf7f2 1395#define DUK_STRIDX_WITH 172 /* 'with' */
7c673cae
FG
1396#define DUK_HEAP_STRING_WITH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WITH)
1397#define DUK_HTHREAD_STRING_WITH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WITH)
11fdf7f2 1398#define DUK_STRIDX_CLASS 173 /* 'class' */
7c673cae
FG
1399#define DUK_HEAP_STRING_CLASS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLASS)
1400#define DUK_HTHREAD_STRING_CLASS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLASS)
11fdf7f2 1401#define DUK_STRIDX_ENUM 174 /* 'enum' */
7c673cae
FG
1402#define DUK_HEAP_STRING_ENUM(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUM)
1403#define DUK_HTHREAD_STRING_ENUM(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUM)
11fdf7f2 1404#define DUK_STRIDX_EXPORT 175 /* 'export' */
7c673cae
FG
1405#define DUK_HEAP_STRING_EXPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORT)
1406#define DUK_HTHREAD_STRING_EXPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXPORT)
11fdf7f2 1407#define DUK_STRIDX_EXTENDS 176 /* 'extends' */
7c673cae
FG
1408#define DUK_HEAP_STRING_EXTENDS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXTENDS)
1409#define DUK_HTHREAD_STRING_EXTENDS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXTENDS)
11fdf7f2 1410#define DUK_STRIDX_IMPORT 177 /* 'import' */
7c673cae
FG
1411#define DUK_HEAP_STRING_IMPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPORT)
1412#define DUK_HTHREAD_STRING_IMPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPORT)
11fdf7f2 1413#define DUK_STRIDX_SUPER 178 /* 'super' */
7c673cae
FG
1414#define DUK_HEAP_STRING_SUPER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SUPER)
1415#define DUK_HTHREAD_STRING_SUPER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SUPER)
11fdf7f2 1416#define DUK_STRIDX_LC_NULL 179 /* 'null' */
7c673cae
FG
1417#define DUK_HEAP_STRING_LC_NULL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NULL)
1418#define DUK_HTHREAD_STRING_LC_NULL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NULL)
11fdf7f2 1419#define DUK_STRIDX_TRUE 180 /* 'true' */
7c673cae
FG
1420#define DUK_HEAP_STRING_TRUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRUE)
1421#define DUK_HTHREAD_STRING_TRUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRUE)
11fdf7f2 1422#define DUK_STRIDX_FALSE 181 /* 'false' */
7c673cae
FG
1423#define DUK_HEAP_STRING_FALSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FALSE)
1424#define DUK_HTHREAD_STRING_FALSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FALSE)
11fdf7f2 1425#define DUK_STRIDX_IMPLEMENTS 182 /* 'implements' */
7c673cae
FG
1426#define DUK_HEAP_STRING_IMPLEMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPLEMENTS)
1427#define DUK_HTHREAD_STRING_IMPLEMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPLEMENTS)
11fdf7f2 1428#define DUK_STRIDX_INTERFACE 183 /* 'interface' */
7c673cae
FG
1429#define DUK_HEAP_STRING_INTERFACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INTERFACE)
1430#define DUK_HTHREAD_STRING_INTERFACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INTERFACE)
11fdf7f2 1431#define DUK_STRIDX_LET 184 /* 'let' */
7c673cae
FG
1432#define DUK_HEAP_STRING_LET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LET)
1433#define DUK_HTHREAD_STRING_LET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LET)
11fdf7f2 1434#define DUK_STRIDX_PACKAGE 185 /* 'package' */
7c673cae
FG
1435#define DUK_HEAP_STRING_PACKAGE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PACKAGE)
1436#define DUK_HTHREAD_STRING_PACKAGE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PACKAGE)
11fdf7f2 1437#define DUK_STRIDX_PRIVATE 186 /* 'private' */
7c673cae
FG
1438#define DUK_HEAP_STRING_PRIVATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PRIVATE)
1439#define DUK_HTHREAD_STRING_PRIVATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PRIVATE)
11fdf7f2 1440#define DUK_STRIDX_PROTECTED 187 /* 'protected' */
7c673cae
FG
1441#define DUK_HEAP_STRING_PROTECTED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTECTED)
1442#define DUK_HTHREAD_STRING_PROTECTED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTECTED)
11fdf7f2 1443#define DUK_STRIDX_PUBLIC 188 /* 'public' */
7c673cae
FG
1444#define DUK_HEAP_STRING_PUBLIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PUBLIC)
1445#define DUK_HTHREAD_STRING_PUBLIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PUBLIC)
11fdf7f2 1446#define DUK_STRIDX_STATIC 189 /* 'static' */
7c673cae
FG
1447#define DUK_HEAP_STRING_STATIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STATIC)
1448#define DUK_HTHREAD_STRING_STATIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STATIC)
11fdf7f2 1449#define DUK_STRIDX_YIELD 190 /* 'yield' */
7c673cae
FG
1450#define DUK_HEAP_STRING_YIELD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_YIELD)
1451#define DUK_HTHREAD_STRING_YIELD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_YIELD)
1452
11fdf7f2
TL
1453#define DUK_HEAP_NUM_STRINGS 191
1454#define DUK_STRIDX_START_RESERVED 146
1455#define DUK_STRIDX_START_STRICT_RESERVED 182
1456#define DUK_STRIDX_END_RESERVED 191 /* exclusive endpoint */
7c673cae 1457
11fdf7f2
TL
1458/* To convert a heap stridx to a token number, subtract
1459 * DUK_STRIDX_START_RESERVED and add DUK_TOK_START_RESERVED.
1460 */
7c673cae 1461#if !defined(DUK_SINGLE_FILE)
11fdf7f2 1462DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[1049];
7c673cae 1463#endif /* !DUK_SINGLE_FILE */
11fdf7f2
TL
1464#define DUK_STRDATA_MAX_STRLEN 17
1465#define DUK_STRDATA_DATA_LENGTH 1049
1466#endif /* DUK_USE_ROM_STRINGS */
7c673cae 1467
11fdf7f2
TL
1468#if defined(DUK_USE_ROM_OBJECTS)
1469#error ROM support not enabled, rerun make_dist.py with --rom-support
1470#else
1471DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor(duk_context *ctx);
1472DUK_INTERNAL_DECL duk_ret_t duk_bi_function_constructor(duk_context *ctx);
1473DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_context *ctx);
1474DUK_INTERNAL_DECL duk_ret_t duk_bi_array_constructor(duk_context *ctx);
1475DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor(duk_context *ctx);
1476DUK_INTERNAL_DECL duk_ret_t duk_bi_boolean_constructor(duk_context *ctx);
1477DUK_INTERNAL_DECL duk_ret_t duk_bi_number_constructor(duk_context *ctx);
1478DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor(duk_context *ctx);
1479DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx);
1480DUK_INTERNAL_DECL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx);
1481DUK_INTERNAL_DECL duk_ret_t duk_bi_type_error_thrower(duk_context *ctx);
1482DUK_INTERNAL_DECL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx);
1483DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_constructor(duk_context *ctx);
1484DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_constructor(duk_context *ctx);
1485DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_constructor(duk_context *ctx);
1486DUK_INTERNAL_DECL duk_ret_t duk_bi_logger_constructor(duk_context *ctx);
1487DUK_INTERNAL_DECL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx);
1488DUK_INTERNAL_DECL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx);
1489DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx);
1490DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx);
1491DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_eval(duk_context *ctx);
1492DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx);
1493DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx);
1494DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_is_nan(duk_context *ctx);
1495DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_is_finite(duk_context *ctx);
1496DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_decode_uri(duk_context *ctx);
1497DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_decode_uri_component(duk_context *ctx);
1498DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_encode_uri(duk_context *ctx);
1499DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_encode_uri_component(duk_context *ctx);
1500DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_escape(duk_context *ctx);
1501DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx);
1502DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx);
1503DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_require(duk_context *ctx);
1504DUK_INTERNAL_DECL duk_ret_t duk_bi_object_getprototype_shared(duk_context *ctx);
1505DUK_INTERNAL_DECL duk_ret_t duk_bi_object_setprototype_shared(duk_context *ctx);
1506DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_context *ctx);
1507DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx);
1508DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_create(duk_context *ctx);
1509DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_define_property(duk_context *ctx);
1510DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_define_properties(duk_context *ctx);
1511DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_context *ctx);
1512DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_context *ctx);
1513DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_context *ctx);
1514DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is_extensible(duk_context *ctx);
1515DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_string(duk_context *ctx);
1516DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_context *ctx);
1517DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_value_of(duk_context *ctx);
1518DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_has_own_property(duk_context *ctx);
1519DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_context *ctx);
1520DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_context *ctx);
1521DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx);
1522DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx);
1523DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_call(duk_context *ctx);
1524DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx);
1525DUK_INTERNAL_DECL duk_ret_t duk_bi_array_constructor_is_array(duk_context *ctx);
1526DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx);
1527DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx);
1528DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx);
1529DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_pop(duk_context *ctx);
1530DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx);
1531DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_reverse(duk_context *ctx);
1532DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx);
1533DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx);
1534DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_sort(duk_context *ctx);
1535DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx);
1536DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx);
1537DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx);
1538DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx);
1539DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx);
1540DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor_from_char_code(duk_context *ctx);
1541DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_to_string(duk_context *ctx);
1542DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_char_at(duk_context *ctx);
1543DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_char_code_at(duk_context *ctx);
1544DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_concat(duk_context *ctx);
1545DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_context *ctx);
1546DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_locale_compare(duk_context *ctx);
1547DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_match(duk_context *ctx);
1548DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx);
1549DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_search(duk_context *ctx);
1550DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_slice(duk_context *ctx);
1551DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx);
1552DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_substring(duk_context *ctx);
1553DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_context *ctx);
1554DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_trim(duk_context *ctx);
1555DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx);
1556DUK_INTERNAL_DECL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx);
1557DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_string(duk_context *ctx);
1558DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_locale_string(duk_context *ctx);
1559DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_value_of(duk_context *ctx);
1560DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_fixed(duk_context *ctx);
1561DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_exponential(duk_context *ctx);
1562DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_precision(duk_context *ctx);
1563DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_parse(duk_context *ctx);
1564DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_utc(duk_context *ctx);
1565DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_now(duk_context *ctx);
1566DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_tostring_shared(duk_context *ctx);
1567DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_to_json(duk_context *ctx);
1568DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_value_of(duk_context *ctx);
1569DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_get_shared(duk_context *ctx);
1570DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_context *ctx);
1571DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_set_time(duk_context *ctx);
1572DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_set_shared(duk_context *ctx);
1573DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_exec(duk_context *ctx);
1574DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_test(duk_context *ctx);
1575DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_to_string(duk_context *ctx);
1576DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx);
1577DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_setter(duk_context *ctx);
1578DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx);
1579DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_setter(duk_context *ctx);
1580DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx);
1581DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_context *ctx);
1582DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx);
1583DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_onearg_shared(duk_context *ctx);
1584DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx);
1585DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_max(duk_context *ctx);
1586DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_min(duk_context *ctx);
1587DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_random(duk_context *ctx);
1588DUK_INTERNAL_DECL duk_ret_t duk_bi_json_object_parse(duk_context *ctx);
1589DUK_INTERNAL_DECL duk_ret_t duk_bi_json_object_stringify(duk_context *ctx);
1590DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_info(duk_context *ctx);
1591DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_act(duk_context *ctx);
1592DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx);
1593DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_fin(duk_context *ctx);
1594DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx);
1595DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_dec(duk_context *ctx);
1596DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_compact(duk_context *ctx);
1597DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_yield(duk_context *ctx);
1598DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_resume(duk_context *ctx);
1599DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_current(duk_context *ctx);
1600DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_prototype_tostring_shared(duk_context *ctx);
1601DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_context *ctx);
1602DUK_INTERNAL_DECL duk_ret_t duk_bi_logger_prototype_fmt(duk_context *ctx);
1603DUK_INTERNAL_DECL duk_ret_t duk_bi_logger_prototype_raw(duk_context *ctx);
1604DUK_INTERNAL_DECL duk_ret_t duk_bi_logger_prototype_log_shared(duk_context *ctx);
1605DUK_INTERNAL_DECL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx);
1606DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx);
1607DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx);
1608DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx);
1609DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_set(duk_context *ctx);
1610DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx);
1611DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx);
1612DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx);
1613DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx);
1614DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx);
1615DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx);
1616DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx);
1617DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx);
1618DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx);
1619DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx);
1620#if !defined(DUK_SINGLE_FILE)
1621DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[149];
1622#endif /* !DUK_SINGLE_FILE */
1623#if defined(DUK_USE_BUILTIN_INITJS)
1624#if !defined(DUK_SINGLE_FILE)
1625DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[204];
1626#endif /* !DUK_SINGLE_FILE */
1627#define DUK_BUILTIN_INITJS_DATA_LENGTH 204
7c673cae 1628#endif /* DUK_USE_BUILTIN_INITJS */
7c673cae
FG
1629#define DUK_BIDX_GLOBAL 0
1630#define DUK_BIDX_GLOBAL_ENV 1
1631#define DUK_BIDX_OBJECT_CONSTRUCTOR 2
1632#define DUK_BIDX_OBJECT_PROTOTYPE 3
1633#define DUK_BIDX_FUNCTION_CONSTRUCTOR 4
1634#define DUK_BIDX_FUNCTION_PROTOTYPE 5
1635#define DUK_BIDX_ARRAY_CONSTRUCTOR 6
1636#define DUK_BIDX_ARRAY_PROTOTYPE 7
1637#define DUK_BIDX_STRING_CONSTRUCTOR 8
1638#define DUK_BIDX_STRING_PROTOTYPE 9
1639#define DUK_BIDX_BOOLEAN_CONSTRUCTOR 10
1640#define DUK_BIDX_BOOLEAN_PROTOTYPE 11
1641#define DUK_BIDX_NUMBER_CONSTRUCTOR 12
1642#define DUK_BIDX_NUMBER_PROTOTYPE 13
1643#define DUK_BIDX_DATE_CONSTRUCTOR 14
1644#define DUK_BIDX_DATE_PROTOTYPE 15
1645#define DUK_BIDX_REGEXP_CONSTRUCTOR 16
1646#define DUK_BIDX_REGEXP_PROTOTYPE 17
1647#define DUK_BIDX_ERROR_CONSTRUCTOR 18
1648#define DUK_BIDX_ERROR_PROTOTYPE 19
1649#define DUK_BIDX_EVAL_ERROR_CONSTRUCTOR 20
1650#define DUK_BIDX_EVAL_ERROR_PROTOTYPE 21
1651#define DUK_BIDX_RANGE_ERROR_CONSTRUCTOR 22
1652#define DUK_BIDX_RANGE_ERROR_PROTOTYPE 23
1653#define DUK_BIDX_REFERENCE_ERROR_CONSTRUCTOR 24
1654#define DUK_BIDX_REFERENCE_ERROR_PROTOTYPE 25
1655#define DUK_BIDX_SYNTAX_ERROR_CONSTRUCTOR 26
1656#define DUK_BIDX_SYNTAX_ERROR_PROTOTYPE 27
1657#define DUK_BIDX_TYPE_ERROR_CONSTRUCTOR 28
1658#define DUK_BIDX_TYPE_ERROR_PROTOTYPE 29
1659#define DUK_BIDX_URI_ERROR_CONSTRUCTOR 30
1660#define DUK_BIDX_URI_ERROR_PROTOTYPE 31
1661#define DUK_BIDX_MATH 32
1662#define DUK_BIDX_JSON 33
1663#define DUK_BIDX_TYPE_ERROR_THROWER 34
1664#define DUK_BIDX_PROXY_CONSTRUCTOR 35
1665#define DUK_BIDX_DUKTAPE 36
1666#define DUK_BIDX_THREAD_CONSTRUCTOR 37
1667#define DUK_BIDX_THREAD_PROTOTYPE 38
1668#define DUK_BIDX_BUFFER_CONSTRUCTOR 39
1669#define DUK_BIDX_BUFFER_PROTOTYPE 40
1670#define DUK_BIDX_POINTER_CONSTRUCTOR 41
1671#define DUK_BIDX_POINTER_PROTOTYPE 42
1672#define DUK_BIDX_LOGGER_CONSTRUCTOR 43
1673#define DUK_BIDX_LOGGER_PROTOTYPE 44
1674#define DUK_BIDX_DOUBLE_ERROR 45
1675#define DUK_BIDX_ARRAYBUFFER_CONSTRUCTOR 46
1676#define DUK_BIDX_ARRAYBUFFER_PROTOTYPE 47
1677#define DUK_BIDX_DATAVIEW_CONSTRUCTOR 48
1678#define DUK_BIDX_DATAVIEW_PROTOTYPE 49
1679#define DUK_BIDX_TYPEDARRAY_PROTOTYPE 50
1680#define DUK_BIDX_INT8ARRAY_CONSTRUCTOR 51
1681#define DUK_BIDX_INT8ARRAY_PROTOTYPE 52
1682#define DUK_BIDX_UINT8ARRAY_CONSTRUCTOR 53
1683#define DUK_BIDX_UINT8ARRAY_PROTOTYPE 54
1684#define DUK_BIDX_UINT8CLAMPEDARRAY_CONSTRUCTOR 55
1685#define DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE 56
1686#define DUK_BIDX_INT16ARRAY_CONSTRUCTOR 57
1687#define DUK_BIDX_INT16ARRAY_PROTOTYPE 58
1688#define DUK_BIDX_UINT16ARRAY_CONSTRUCTOR 59
1689#define DUK_BIDX_UINT16ARRAY_PROTOTYPE 60
1690#define DUK_BIDX_INT32ARRAY_CONSTRUCTOR 61
1691#define DUK_BIDX_INT32ARRAY_PROTOTYPE 62
1692#define DUK_BIDX_UINT32ARRAY_CONSTRUCTOR 63
1693#define DUK_BIDX_UINT32ARRAY_PROTOTYPE 64
1694#define DUK_BIDX_FLOAT32ARRAY_CONSTRUCTOR 65
1695#define DUK_BIDX_FLOAT32ARRAY_PROTOTYPE 66
1696#define DUK_BIDX_FLOAT64ARRAY_CONSTRUCTOR 67
1697#define DUK_BIDX_FLOAT64ARRAY_PROTOTYPE 68
1698#define DUK_BIDX_NODEJS_BUFFER_CONSTRUCTOR 69
1699#define DUK_BIDX_NODEJS_BUFFER_PROTOTYPE 70
7c673cae 1700#define DUK_NUM_BUILTINS 71
11fdf7f2
TL
1701#define DUK_NUM_BIDX_BUILTINS 71
1702#define DUK_NUM_ALL_BUILTINS 71
1703#if defined(DUK_USE_DOUBLE_LE)
1704#if !defined(DUK_SINGLE_FILE)
1705DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3833];
1706#endif /* !DUK_SINGLE_FILE */
1707#define DUK_BUILTINS_DATA_LENGTH 3833
1708#elif defined(DUK_USE_DOUBLE_BE)
1709#if !defined(DUK_SINGLE_FILE)
1710DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3833];
1711#endif /* !DUK_SINGLE_FILE */
1712#define DUK_BUILTINS_DATA_LENGTH 3833
1713#elif defined(DUK_USE_DOUBLE_ME)
1714#if !defined(DUK_SINGLE_FILE)
1715DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3833];
1716#endif /* !DUK_SINGLE_FILE */
1717#define DUK_BUILTINS_DATA_LENGTH 3833
7c673cae
FG
1718#else
1719#error invalid endianness defines
1720#endif
11fdf7f2 1721#endif /* DUK_USE_ROM_OBJECTS */
7c673cae 1722#endif /* DUK_BUILTINS_H_INCLUDED */
7c673cae 1723
7c673cae
FG
1724/*
1725 * Utilities
1726 */
1727
1728#ifndef DUK_UTIL_H_INCLUDED
1729#define DUK_UTIL_H_INCLUDED
1730
1731#define DUK_UTIL_MIN_HASH_PRIME 17 /* must match genhashsizes.py */
1732
1733#define DUK_UTIL_GET_HASH_PROBE_STEP(hash) (duk_util_probe_steps[(hash) & 0x1f])
1734
1735/*
1736 * Endian conversion
1737 */
1738
1739#if defined(DUK_USE_INTEGER_LE)
1740#define DUK_HTON32(x) DUK_BSWAP32((x))
1741#define DUK_NTOH32(x) DUK_BSWAP32((x))
1742#define DUK_HTON16(x) DUK_BSWAP16((x))
1743#define DUK_NTOH16(x) DUK_BSWAP16((x))
1744#elif defined(DUK_USE_INTEGER_BE)
1745#define DUK_HTON32(x) (x)
1746#define DUK_NTOH32(x) (x)
1747#define DUK_HTON16(x) (x)
1748#define DUK_NTOH16(x) (x)
1749#else
1750#error internal error, endianness defines broken
1751#endif
1752
1753/*
1754 * Bitstream decoder
1755 */
1756
1757struct duk_bitdecoder_ctx {
1758 const duk_uint8_t *data;
1759 duk_size_t offset;
1760 duk_size_t length;
1761 duk_uint32_t currval;
1762 duk_small_int_t currbits;
1763};
1764
1765/*
1766 * Bitstream encoder
1767 */
1768
1769struct duk_bitencoder_ctx {
1770 duk_uint8_t *data;
1771 duk_size_t offset;
1772 duk_size_t length;
1773 duk_uint32_t currval;
1774 duk_small_int_t currbits;
1775 duk_small_int_t truncated;
1776};
1777
1778/*
1779 * Raw write/read macros for big endian, unaligned basic values.
1780 * Caller ensures there's enough space. The macros update the pointer
1781 * argument automatically on resizes. The idiom seems a bit odd, but
1782 * leads to compact code.
1783 */
1784
1785#define DUK_RAW_WRITE_U8(ptr,val) do { \
1786 *(ptr)++ = (duk_uint8_t) (val); \
1787 } while (0)
1788#define DUK_RAW_WRITE_U16_BE(ptr,val) duk_raw_write_u16_be(&(ptr), (duk_uint16_t) (val))
1789#define DUK_RAW_WRITE_U32_BE(ptr,val) duk_raw_write_u32_be(&(ptr), (duk_uint32_t) (val))
1790#define DUK_RAW_WRITE_DOUBLE_BE(ptr,val) duk_raw_write_double_be(&(ptr), (duk_double_t) (val))
1791#define DUK_RAW_WRITE_XUTF8(ptr,val) do { \
1792 /* 'ptr' is evaluated both as LHS and RHS. */ \
1793 duk_uint8_t *duk__ptr; \
1794 duk_small_int_t duk__len; \
1795 duk__ptr = (duk_uint8_t *) (ptr); \
1796 duk__len = duk_unicode_encode_xutf8((duk_ucodepoint_t) (val), duk__ptr); \
1797 duk__ptr += duk__len; \
1798 (ptr) = duk__ptr; \
1799 } while (0)
1800#define DUK_RAW_WRITE_CESU8(ptr,val) do { \
1801 /* 'ptr' is evaluated both as LHS and RHS. */ \
1802 duk_uint8_t *duk__ptr; \
1803 duk_small_int_t duk__len; \
1804 duk__ptr = (duk_uint8_t *) (ptr); \
1805 duk__len = duk_unicode_encode_cesu8((duk_ucodepoint_t) (val), duk__ptr); \
1806 duk__ptr += duk__len; \
1807 (ptr) = duk__ptr; \
1808 } while (0)
1809
1810#define DUK_RAW_READ_U8(ptr) ((duk_uint8_t) (*(ptr)++))
1811#define DUK_RAW_READ_U16_BE(ptr) duk_raw_read_u16_be(&(ptr));
1812#define DUK_RAW_READ_U32_BE(ptr) duk_raw_read_u32_be(&(ptr));
1813#define DUK_RAW_READ_DOUBLE_BE(ptr) duk_raw_read_double_be(&(ptr));
1814
1815/*
1816 * Buffer writer (dynamic buffer only)
1817 *
1818 * Helper for writing to a dynamic buffer with a concept of a "spare" area
1819 * to reduce resizes. You can ensure there is enough space beforehand and
1820 * then write for a while without further checks, relying on a stable data
1821 * pointer. Spare handling is automatic so call sites only indicate how
1822 * much data they need right now.
1823 *
1824 * There are several ways to write using bufwriter. The best approach
1825 * depends mainly on how much performance matters over code footprint.
1826 * The key issues are (1) ensuring there is space and (2) keeping the
1827 * pointers consistent. Fast code should ensure space for multiple writes
1828 * with one ensure call. Fastest inner loop code can temporarily borrow
1829 * the 'p' pointer but must write it back eventually.
1830 *
1831 * Be careful to ensure all macro arguments (other than static pointers like
1832 * 'thr' and 'bw_ctx') are evaluated exactly once, using temporaries if
1833 * necessary (if that's not possible, there should be a note near the macro).
1834 * Buffer write arguments often contain arithmetic etc so this is
1835 * particularly important here.
1836 */
1837
1838/* XXX: Migrate bufwriter and other read/write helpers to its own header? */
1839
1840struct duk_bufwriter_ctx {
1841 duk_uint8_t *p;
1842 duk_uint8_t *p_base;
1843 duk_uint8_t *p_limit;
1844 duk_hbuffer_dynamic *buf;
1845};
1846
1847#define DUK_BW_SPARE_ADD 64
1848#define DUK_BW_SPARE_SHIFT 4 /* 2^4 -> 1/16 = 6.25% spare */
1849
1850/* Initialization and finalization (compaction), converting to other types. */
1851
1852#define DUK_BW_INIT_PUSHBUF(thr,bw_ctx,sz) do { \
1853 duk_bw_init_pushbuf((thr), (bw_ctx), (sz)); \
1854 } while (0)
1855#define DUK_BW_INIT_WITHBUF(thr,bw_ctx,buf) do { \
1856 duk_bw_init((thr), (bw_ctx), (buf)); \
1857 } while (0)
1858#define DUK_BW_COMPACT(thr,bw_ctx) do { \
1859 /* Make underlying buffer compact to match DUK_BW_GET_SIZE(). */ \
1860 duk_bw_compact((thr), (bw_ctx)); \
1861 } while (0)
1862#define DUK_BW_PUSH_AS_STRING(thr,bw_ctx) do { \
1863 duk_push_lstring((duk_context *) (thr), \
1864 (const char *) (bw_ctx)->p_base, \
1865 (duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)); \
1866 } while (0)
1867/* Pointers may be NULL for a while when 'buf' size is zero and before any
1868 * ENSURE calls have been made. Once an ENSURE has been made, the pointers
1869 * are required to be non-NULL so that it's always valid to use memcpy() and
1870 * memmove(), even for zero size.
1871 */
1872#define DUK_BW_ASSERT_VALID_EXPR(thr,bw_ctx) \
1873 DUK_ASSERT_EXPR((bw_ctx) != NULL && \
1874 (bw_ctx)->buf != NULL && \
1875 ((DUK_HBUFFER_DYNAMIC_GET_SIZE((bw_ctx)->buf) == 0) || \
1876 ((bw_ctx)->p != NULL && \
1877 (bw_ctx)->p_base != NULL && \
1878 (bw_ctx)->p_limit != NULL && \
1879 (bw_ctx)->p_limit >= (bw_ctx)->p_base && \
1880 (bw_ctx)->p >= (bw_ctx)->p_base && \
1881 (bw_ctx)->p <= (bw_ctx)->p_limit)))
1882#define DUK_BW_ASSERT_VALID(thr,bw_ctx) do { \
1883 DUK_BW_ASSERT_VALID_EXPR((thr), (bw_ctx)); \
1884 } while (0)
1885
1886/* Working with the pointer and current size. */
1887
1888#define DUK_BW_GET_PTR(thr,bw_ctx) \
1889 ((bw_ctx)->p)
1890#define DUK_BW_SET_PTR(thr,bw_ctx,ptr) do { \
1891 (bw_ctx)->p = (ptr); \
1892 } while (0)
1893#define DUK_BW_ADD_PTR(thr,bw_ctx,delta) do { \
1894 (bw_ctx)->p += (delta); \
1895 } while (0)
1896#define DUK_BW_GET_BASEPTR(thr,bw_ctx) \
1897 ((bw_ctx)->p_base)
1898#define DUK_BW_GET_LIMITPTR(thr,bw_ctx) \
1899 ((bw_ctx)->p_limit)
1900#define DUK_BW_GET_SIZE(thr,bw_ctx) \
1901 ((duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base))
1902#define DUK_BW_SET_SIZE(thr,bw_ctx,sz) do { \
1903 DUK_ASSERT((duk_size_t) (sz) <= (duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)); \
1904 (bw_ctx)->p = (bw_ctx)->p_base + (sz); \
1905 } while (0)
1906#define DUK_BW_RESET_SIZE(thr,bw_ctx) do { \
1907 /* Reset to zero size, keep current limit. */ \
1908 (bw_ctx)->p = (bw_ctx)->p_base; \
1909 } while (0)
1910#define DUK_BW_GET_BUFFER(thr,bw_ctx) \
1911 ((bw_ctx)->buf)
1912
1913/* Ensuring (reserving) space. */
1914
1915#define DUK_BW_ENSURE(thr,bw_ctx,sz) do { \
1916 duk_size_t duk__sz, duk__space; \
1917 DUK_BW_ASSERT_VALID((thr), (bw_ctx)); \
1918 duk__sz = (sz); \
1919 duk__space = (duk_size_t) ((bw_ctx)->p_limit - (bw_ctx)->p); \
1920 if (duk__space < duk__sz) { \
1921 (void) duk_bw_resize((thr), (bw_ctx), duk__sz); \
1922 } \
1923 } while (0)
1924/* NOTE: Multiple evaluation of 'ptr' in this macro. */
1925/* XXX: Rework to use an always-inline function? */
1926#define DUK_BW_ENSURE_RAW(thr,bw_ctx,sz,ptr) \
1927 (((duk_size_t) ((bw_ctx)->p_limit - (ptr)) >= (sz)) ? \
1928 (ptr) : \
1929 ((bw_ctx)->p = (ptr), duk_bw_resize((thr),(bw_ctx),(sz))))
1930#define DUK_BW_ENSURE_GETPTR(thr,bw_ctx,sz) \
1931 DUK_BW_ENSURE_RAW((thr), (bw_ctx), (sz), (bw_ctx)->p)
1932#define DUK_BW_ASSERT_SPACE_EXPR(thr,bw_ctx,sz) \
1933 (DUK_BW_ASSERT_VALID_EXPR((thr), (bw_ctx)), \
1934 DUK_ASSERT_EXPR((duk_size_t) ((bw_ctx)->p_limit - (bw_ctx)->p) >= (duk_size_t) (sz)))
1935#define DUK_BW_ASSERT_SPACE(thr,bw_ctx,sz) do { \
1936 DUK_BW_ASSERT_SPACE_EXPR((thr), (bw_ctx), (sz)); \
1937 } while (0)
1938
1939/* Miscellaneous. */
1940
1941#define DUK_BW_SETPTR_AND_COMPACT(thr,bw_ctx,ptr) do { \
1942 (bw_ctx)->p = (ptr); \
1943 duk_bw_compact((thr), (bw_ctx)); \
1944 } while (0)
1945
1946/* Fast write calls which assume you control the spare beforehand.
1947 * Multibyte write variants exist and use a temporary write pointer
1948 * because byte writes alias with anything: with a stored pointer
1949 * explicit pointer load/stores get generated (e.g. gcc -Os).
1950 */
1951
1952#define DUK_BW_WRITE_RAW_U8(thr,bw_ctx,val) do { \
1953 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 1); \
1954 *(bw_ctx)->p++ = (duk_uint8_t) (val); \
1955 } while (0)
1956#define DUK_BW_WRITE_RAW_U8_2(thr,bw_ctx,val1,val2) do { \
1957 duk_uint8_t *duk__p; \
1958 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 2); \
1959 duk__p = (bw_ctx)->p; \
1960 *duk__p++ = (duk_uint8_t) (val1); \
1961 *duk__p++ = (duk_uint8_t) (val2); \
1962 (bw_ctx)->p = duk__p; \
1963 } while (0)
1964#define DUK_BW_WRITE_RAW_U8_3(thr,bw_ctx,val1,val2,val3) do { \
1965 duk_uint8_t *duk__p; \
1966 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 3); \
1967 duk__p = (bw_ctx)->p; \
1968 *duk__p++ = (duk_uint8_t) (val1); \
1969 *duk__p++ = (duk_uint8_t) (val2); \
1970 *duk__p++ = (duk_uint8_t) (val3); \
1971 (bw_ctx)->p = duk__p; \
1972 } while (0)
1973#define DUK_BW_WRITE_RAW_U8_4(thr,bw_ctx,val1,val2,val3,val4) do { \
1974 duk_uint8_t *duk__p; \
1975 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 4); \
1976 duk__p = (bw_ctx)->p; \
1977 *duk__p++ = (duk_uint8_t) (val1); \
1978 *duk__p++ = (duk_uint8_t) (val2); \
1979 *duk__p++ = (duk_uint8_t) (val3); \
1980 *duk__p++ = (duk_uint8_t) (val4); \
1981 (bw_ctx)->p = duk__p; \
1982 } while (0)
1983#define DUK_BW_WRITE_RAW_U8_5(thr,bw_ctx,val1,val2,val3,val4,val5) do { \
1984 duk_uint8_t *duk__p; \
1985 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 5); \
1986 duk__p = (bw_ctx)->p; \
1987 *duk__p++ = (duk_uint8_t) (val1); \
1988 *duk__p++ = (duk_uint8_t) (val2); \
1989 *duk__p++ = (duk_uint8_t) (val3); \
1990 *duk__p++ = (duk_uint8_t) (val4); \
1991 *duk__p++ = (duk_uint8_t) (val5); \
1992 (bw_ctx)->p = duk__p; \
1993 } while (0)
1994#define DUK_BW_WRITE_RAW_U8_6(thr,bw_ctx,val1,val2,val3,val4,val5,val6) do { \
1995 duk_uint8_t *duk__p; \
1996 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 6); \
1997 duk__p = (bw_ctx)->p; \
1998 *duk__p++ = (duk_uint8_t) (val1); \
1999 *duk__p++ = (duk_uint8_t) (val2); \
2000 *duk__p++ = (duk_uint8_t) (val3); \
2001 *duk__p++ = (duk_uint8_t) (val4); \
2002 *duk__p++ = (duk_uint8_t) (val5); \
2003 *duk__p++ = (duk_uint8_t) (val6); \
2004 (bw_ctx)->p = duk__p; \
2005 } while (0)
2006#define DUK_BW_WRITE_RAW_XUTF8(thr,bw_ctx,cp) do { \
2007 duk_ucodepoint_t duk__cp; \
2008 duk_small_int_t duk__enc_len; \
2009 duk__cp = (cp); \
2010 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), duk_unicode_get_xutf8_length(duk__cp)); \
2011 duk__enc_len = duk_unicode_encode_xutf8(duk__cp, (bw_ctx)->p); \
2012 (bw_ctx)->p += duk__enc_len; \
2013 } while (0)
2014#define DUK_BW_WRITE_RAW_CESU8(thr,bw_ctx,cp) do { \
2015 duk_ucodepoint_t duk__cp; \
2016 duk_small_int_t duk__enc_len; \
2017 duk__cp = (duk_ucodepoint_t) (cp); \
2018 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), duk_unicode_get_cesu8_length(duk__cp)); \
2019 duk__enc_len = duk_unicode_encode_cesu8(duk__cp, (bw_ctx)->p); \
2020 (bw_ctx)->p += duk__enc_len; \
2021 } while (0)
2022/* XXX: add temporary duk__p pointer here too; sharing */
2023#define DUK_BW_WRITE_RAW_BYTES(thr,bw_ctx,valptr,valsz) do { \
2024 const void *duk__valptr; \
2025 duk_size_t duk__valsz; \
2026 duk__valptr = (const void *) (valptr); \
2027 duk__valsz = (duk_size_t) (valsz); \
2028 DUK_MEMCPY((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \
2029 (bw_ctx)->p += duk__valsz; \
2030 } while (0)
2031#define DUK_BW_WRITE_RAW_CSTRING(thr,bw_ctx,val) do { \
2032 const duk_uint8_t *duk__val; \
2033 duk_size_t duk__val_len; \
2034 duk__val = (const duk_uint8_t *) (val); \
2035 duk__val_len = DUK_STRLEN((const char *) duk__val); \
2036 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \
2037 (bw_ctx)->p += duk__val_len; \
2038 } while (0)
2039#define DUK_BW_WRITE_RAW_HSTRING(thr,bw_ctx,val) do { \
2040 duk_size_t duk__val_len; \
2041 duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \
2042 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \
2043 (bw_ctx)->p += duk__val_len; \
2044 } while (0)
2045#define DUK_BW_WRITE_RAW_HBUFFER(thr,bw_ctx,val) do { \
2046 duk_size_t duk__val_len; \
2047 duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \
2048 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2049 (bw_ctx)->p += duk__val_len; \
2050 } while (0)
2051#define DUK_BW_WRITE_RAW_HBUFFER_FIXED(thr,bw_ctx,val) do { \
2052 duk_size_t duk__val_len; \
2053 duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \
2054 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2055 (bw_ctx)->p += duk__val_len; \
2056 } while (0)
2057#define DUK_BW_WRITE_RAW_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \
2058 duk_size_t duk__val_len; \
2059 duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \
2060 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2061 (bw_ctx)->p += duk__val_len; \
2062 } while (0)
2063
2064/* Append bytes from a slice already in the buffer. */
2065#define DUK_BW_WRITE_RAW_SLICE(thr,bw,dst_off,dst_len) \
2066 duk_bw_write_raw_slice((thr), (bw), (dst_off), (dst_len))
2067
2068/* Insert bytes in the middle of the buffer from an external buffer. */
2069#define DUK_BW_INSERT_RAW_BYTES(thr,bw,dst_off,buf,len) \
2070 duk_bw_insert_raw_bytes((thr), (bw), (dst_off), (buf), (len))
2071
2072/* Insert bytes in the middle of the buffer from a slice already
2073 * in the buffer. Source offset is interpreted "before" the operation.
2074 */
2075#define DUK_BW_INSERT_RAW_SLICE(thr,bw,dst_off,src_off,len) \
2076 duk_bw_insert_raw_slice((thr), (bw), (dst_off), (src_off), (len))
2077
2078/* Insert a reserved area somewhere in the buffer; caller fills it.
2079 * Evaluates to a (duk_uint_t *) pointing to the start of the reserved
2080 * area for convenience.
2081 */
2082#define DUK_BW_INSERT_RAW_AREA(thr,bw,off,len) \
2083 duk_bw_insert_raw_area((thr), (bw), (off), (len))
2084
2085/* Remove a slice from inside buffer. */
2086#define DUK_BW_REMOVE_RAW_SLICE(thr,bw,off,len) \
2087 duk_bw_remove_raw_slice((thr), (bw), (off), (len))
2088
2089/* Safe write calls which will ensure space first. */
2090
2091#define DUK_BW_WRITE_ENSURE_U8(thr,bw_ctx,val) do { \
2092 DUK_BW_ENSURE((thr), (bw_ctx), 1); \
2093 DUK_BW_WRITE_RAW_U8((thr), (bw_ctx), (val)); \
2094 } while (0)
2095#define DUK_BW_WRITE_ENSURE_U8_2(thr,bw_ctx,val1,val2) do { \
2096 DUK_BW_ENSURE((thr), (bw_ctx), 2); \
2097 DUK_BW_WRITE_RAW_U8_2((thr), (bw_ctx), (val1), (val2)); \
2098 } while (0)
2099#define DUK_BW_WRITE_ENSURE_U8_3(thr,bw_ctx,val1,val2,val3) do { \
2100 DUK_BW_ENSURE((thr), (bw_ctx), 3); \
2101 DUK_BW_WRITE_RAW_U8_3((thr), (bw_ctx), (val1), (val2), (val3)); \
2102 } while (0)
2103#define DUK_BW_WRITE_ENSURE_U8_4(thr,bw_ctx,val1,val2,val3,val4) do { \
2104 DUK_BW_ENSURE((thr), (bw_ctx), 4); \
2105 DUK_BW_WRITE_RAW_U8_4((thr), (bw_ctx), (val1), (val2), (val3), (val4)); \
2106 } while (0)
2107#define DUK_BW_WRITE_ENSURE_U8_5(thr,bw_ctx,val1,val2,val3,val4,val5) do { \
2108 DUK_BW_ENSURE((thr), (bw_ctx), 5); \
2109 DUK_BW_WRITE_RAW_U8_5((thr), (bw_ctx), (val1), (val2), (val3), (val4), (val5)); \
2110 } while (0)
2111#define DUK_BW_WRITE_ENSURE_U8_6(thr,bw_ctx,val1,val2,val3,val4,val5,val6) do { \
2112 DUK_BW_ENSURE((thr), (bw_ctx), 6); \
2113 DUK_BW_WRITE_RAW_U8_6((thr), (bw_ctx), (val1), (val2), (val3), (val4), (val5), (val6)); \
2114 } while (0)
2115#define DUK_BW_WRITE_ENSURE_XUTF8(thr,bw_ctx,cp) do { \
2116 DUK_BW_ENSURE((thr), (bw_ctx), DUK_UNICODE_MAX_XUTF8_LENGTH); \
2117 DUK_BW_WRITE_RAW_XUTF8((thr), (bw_ctx), (cp)); \
2118 } while (0)
2119#define DUK_BW_WRITE_ENSURE_CESU8(thr,bw_ctx,cp) do { \
2120 DUK_BW_ENSURE((thr), (bw_ctx), DUK_UNICODE_MAX_CESU8_LENGTH); \
2121 DUK_BW_WRITE_RAW_CESU8((thr), (bw_ctx), (cp)); \
2122 } while (0)
2123/* XXX: add temporary duk__p pointer here too; sharing */
2124#define DUK_BW_WRITE_ENSURE_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_BW_ENSURE((thr), (bw_ctx), duk__valsz); \
2130 DUK_MEMCPY((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \
2131 (bw_ctx)->p += duk__valsz; \
2132 } while (0)
2133#define DUK_BW_WRITE_ENSURE_CSTRING(thr,bw_ctx,val) do { \
2134 const duk_uint8_t *duk__val; \
2135 duk_size_t duk__val_len; \
2136 duk__val = (const duk_uint8_t *) (val); \
2137 duk__val_len = DUK_STRLEN((const char *) duk__val); \
2138 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
2139 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \
2140 (bw_ctx)->p += duk__val_len; \
2141 } while (0)
2142#define DUK_BW_WRITE_ENSURE_HSTRING(thr,bw_ctx,val) do { \
2143 duk_size_t duk__val_len; \
2144 duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \
2145 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
2146 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \
2147 (bw_ctx)->p += duk__val_len; \
2148 } while (0)
2149#define DUK_BW_WRITE_ENSURE_HBUFFER(thr,bw_ctx,val) do { \
2150 duk_size_t duk__val_len; \
2151 duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \
2152 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
2153 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2154 (bw_ctx)->p += duk__val_len; \
2155 } while (0)
2156#define DUK_BW_WRITE_ENSURE_HBUFFER_FIXED(thr,bw_ctx,val) do { \
2157 duk_size_t duk__val_len; \
2158 duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \
2159 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
2160 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2161 (bw_ctx)->p += duk__val_len; \
2162 } while (0)
2163#define DUK_BW_WRITE_ENSURE_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \
2164 duk_size_t duk__val_len; \
2165 duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \
2166 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
2167 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2168 (bw_ctx)->p += duk__val_len; \
2169 } while (0)
2170
2171#define DUK_BW_WRITE_ENSURE_SLICE(thr,bw,dst_off,dst_len) \
2172 duk_bw_write_ensure_slice((thr), (bw), (dst_off), (dst_len))
2173#define DUK_BW_INSERT_ENSURE_BYTES(thr,bw,dst_off,buf,len) \
2174 duk_bw_insert_ensure_bytes((thr), (bw), (dst_off), (buf), (len))
2175#define DUK_BW_INSERT_ENSURE_SLICE(thr,bw,dst_off,src_off,len) \
2176 duk_bw_insert_ensure_slice((thr), (bw), (dst_off), (src_off), (len))
2177#define DUK_BW_INSERT_ENSURE_AREA(thr,bw,off,len) \
2178 /* Evaluates to (duk_uint8_t *) pointing to start of area. */ \
2179 duk_bw_insert_ensure_area((thr), (bw), (off), (len))
2180#define DUK_BW_REMOVE_ENSURE_SLICE(thr,bw,off,len) \
2181 /* No difference between raw/ensure because the buffer shrinks. */ \
2182 DUK_BW_REMOVE_RAW_SLICE((thr), (bw), (off), (len))
2183
2184/*
2185 * Externs and prototypes
2186 */
2187
2188#if !defined(DUK_SINGLE_FILE)
11fdf7f2
TL
2189DUK_INTERNAL_DECL const duk_uint8_t duk_lc_digits[36];
2190DUK_INTERNAL_DECL const duk_uint8_t duk_uc_nybbles[16];
2191DUK_INTERNAL_DECL const duk_int8_t duk_hex_dectab[256];
2192#if defined(DUK_USE_HEX_FASTPATH)
2193DUK_INTERNAL_DECL const duk_int16_t duk_hex_dectab_shift4[256];
2194DUK_INTERNAL_DECL const duk_uint16_t duk_hex_enctab[256];
2195#endif
2196#if defined(DUK_USE_BASE64_FASTPATH)
2197DUK_INTERNAL_DECL const duk_uint8_t duk_base64_enctab[64];
2198DUK_INTERNAL_DECL const duk_int8_t duk_base64_dectab[256];
2199#endif
7c673cae
FG
2200#endif /* !DUK_SINGLE_FILE */
2201
2202/* Note: assumes that duk_util_probe_steps size is 32 */
2203#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE)
2204#if !defined(DUK_SINGLE_FILE)
2205DUK_INTERNAL_DECL duk_uint8_t duk_util_probe_steps[32];
2206#endif /* !DUK_SINGLE_FILE */
2207#endif
2208
11fdf7f2 2209#if defined(DUK_USE_STRHASH_DENSE)
7c673cae 2210DUK_INTERNAL_DECL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed);
11fdf7f2 2211#endif
7c673cae
FG
2212
2213#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE)
2214DUK_INTERNAL_DECL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size);
2215#endif
2216
2217DUK_INTERNAL_DECL duk_int32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits);
2218DUK_INTERNAL_DECL duk_small_int_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx);
2219DUK_INTERNAL_DECL duk_int32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value);
2220
2221DUK_INTERNAL_DECL void duk_be_encode(duk_bitencoder_ctx *ctx, duk_uint32_t data, duk_small_int_t bits);
2222DUK_INTERNAL_DECL void duk_be_finish(duk_bitencoder_ctx *ctx);
2223
2224DUK_INTERNAL_DECL duk_uint32_t duk_util_tinyrandom_get_bits(duk_hthread *thr, duk_small_int_t n);
2225DUK_INTERNAL_DECL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr);
2226
2227DUK_INTERNAL_DECL void duk_bw_init(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_hbuffer_dynamic *h_buf);
2228DUK_INTERNAL_DECL void duk_bw_init_pushbuf(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t buf_size);
2229DUK_INTERNAL_DECL duk_uint8_t *duk_bw_resize(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t sz);
2230DUK_INTERNAL_DECL void duk_bw_compact(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx);
2231DUK_INTERNAL_DECL void duk_bw_write_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len);
2232DUK_INTERNAL_DECL void duk_bw_write_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len);
2233DUK_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);
2234DUK_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);
2235DUK_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);
2236DUK_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);
2237DUK_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);
2238DUK_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);
2239DUK_INTERNAL_DECL void duk_bw_remove_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len);
2240/* No duk_bw_remove_ensure_slice(), functionality would be identical. */
2241
2242DUK_INTERNAL_DECL duk_uint16_t duk_raw_read_u16_be(duk_uint8_t **p);
2243DUK_INTERNAL_DECL duk_uint32_t duk_raw_read_u32_be(duk_uint8_t **p);
2244DUK_INTERNAL_DECL duk_double_t duk_raw_read_double_be(duk_uint8_t **p);
2245DUK_INTERNAL_DECL void duk_raw_write_u16_be(duk_uint8_t **p, duk_uint16_t val);
2246DUK_INTERNAL_DECL void duk_raw_write_u32_be(duk_uint8_t **p, duk_uint32_t val);
2247DUK_INTERNAL_DECL void duk_raw_write_double_be(duk_uint8_t **p, duk_double_t val);
2248
2249#if defined(DUK_USE_DEBUGGER_SUPPORT) /* For now only needed by the debugger. */
2250DUK_INTERNAL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len);
2251#endif
2252
2253#endif /* DUK_UTIL_H_INCLUDED */
7c673cae
FG
2254/*
2255 * Shared error messages: declarations and macros
2256 *
2257 * Error messages are accessed through macros with fine-grained, explicit
2258 * error message distinctions. Concrete error messages are selected by the
2259 * macros and multiple macros can map to the same concrete string to save
2260 * on code footprint. This allows flexible footprint/verbosity tuning with
2261 * minimal code impact. There are a few limitations to this approach:
2262 * (1) switching between plain messages and format strings doesn't work
2263 * conveniently, and (2) conditional strings are a bit awkward to handle.
2264 *
2265 * Because format strings behave differently in the call site (they need to
2266 * be followed by format arguments), they have a special prefix (DUK_STR_FMT_
2267 * and duk_str_fmt_).
2268 *
2269 * On some compilers using explicit shared strings is preferable; on others
2270 * it may be better to use straight literals because the compiler will combine
2271 * them anyway, and such strings won't end up unnecessarily in a symbol table.
2272 */
2273
2274#ifndef DUK_ERRMSG_H_INCLUDED
2275#define DUK_ERRMSG_H_INCLUDED
2276
2277#define DUK_STR_INTERNAL_ERROR duk_str_internal_error
2278#define DUK_STR_INVALID_COUNT duk_str_invalid_count
2279#define DUK_STR_INVALID_CALL_ARGS duk_str_invalid_call_args
2280#define DUK_STR_NOT_CONSTRUCTABLE duk_str_not_constructable
2281#define DUK_STR_NOT_CALLABLE duk_str_not_callable
2282#define DUK_STR_NOT_EXTENSIBLE duk_str_not_extensible
2283#define DUK_STR_NOT_WRITABLE duk_str_not_writable
2284#define DUK_STR_NOT_CONFIGURABLE duk_str_not_configurable
2285
2286#if !defined(DUK_SINGLE_FILE)
2287DUK_INTERNAL_DECL const char *duk_str_internal_error;
2288DUK_INTERNAL_DECL const char *duk_str_invalid_count;
2289DUK_INTERNAL_DECL const char *duk_str_invalid_call_args;
2290DUK_INTERNAL_DECL const char *duk_str_not_constructable;
2291DUK_INTERNAL_DECL const char *duk_str_not_callable;
2292DUK_INTERNAL_DECL const char *duk_str_not_extensible;
2293DUK_INTERNAL_DECL const char *duk_str_not_writable;
2294DUK_INTERNAL_DECL const char *duk_str_not_configurable;
2295#endif /* !DUK_SINGLE_FILE */
2296
2297#define DUK_STR_INVALID_CONTEXT duk_str_invalid_context
11fdf7f2 2298#define DUK_STR_INVALID_INDEX duk_str_invalid_call_args
7c673cae 2299#define DUK_STR_PUSH_BEYOND_ALLOC_STACK duk_str_push_beyond_alloc_stack
11fdf7f2
TL
2300#define DUK_STR_NOT_UNDEFINED duk_str_unexpected_type
2301#define DUK_STR_NOT_NULL duk_str_unexpected_type
2302#define DUK_STR_NOT_BOOLEAN duk_str_unexpected_type
2303#define DUK_STR_NOT_NUMBER duk_str_unexpected_type
2304#define DUK_STR_NOT_STRING duk_str_unexpected_type
2305#define DUK_STR_NOT_OBJECT duk_str_unexpected_type
2306#define DUK_STR_NOT_POINTER duk_str_unexpected_type
2307#define DUK_STR_NOT_BUFFER duk_str_not_buffer /* still in use with verbose messages */
7c673cae 2308#define DUK_STR_UNEXPECTED_TYPE duk_str_unexpected_type
11fdf7f2
TL
2309#define DUK_STR_NOT_THREAD duk_str_unexpected_type
2310#define DUK_STR_NOT_COMPILEDFUNCTION duk_str_unexpected_type
2311#define DUK_STR_NOT_NATIVEFUNCTION duk_str_unexpected_type
2312#define DUK_STR_NOT_C_FUNCTION duk_str_unexpected_type
2313#define DUK_STR_NOT_FUNCTION duk_str_unexpected_type
2314#define DUK_STR_NOT_REGEXP duk_str_unexpected_type
7c673cae
FG
2315#define DUK_STR_DEFAULTVALUE_COERCE_FAILED duk_str_defaultvalue_coerce_failed
2316#define DUK_STR_NUMBER_OUTSIDE_RANGE duk_str_number_outside_range
2317#define DUK_STR_NOT_OBJECT_COERCIBLE duk_str_not_object_coercible
2318#define DUK_STR_STRING_TOO_LONG duk_str_string_too_long
2319#define DUK_STR_BUFFER_TOO_LONG duk_str_buffer_too_long
2320#define DUK_STR_SPRINTF_TOO_LONG duk_str_sprintf_too_long
2321#define DUK_STR_ALLOC_FAILED duk_str_alloc_failed
2322#define DUK_STR_POP_TOO_MANY duk_str_pop_too_many
2323#define DUK_STR_WRONG_BUFFER_TYPE duk_str_wrong_buffer_type
7c673cae
FG
2324#define DUK_STR_ENCODE_FAILED duk_str_encode_failed
2325#define DUK_STR_DECODE_FAILED duk_str_decode_failed
2326#define DUK_STR_NO_SOURCECODE duk_str_no_sourcecode
2327#define DUK_STR_CONCAT_RESULT_TOO_LONG duk_str_concat_result_too_long
2328#define DUK_STR_UNIMPLEMENTED duk_str_unimplemented
2329#define DUK_STR_UNSUPPORTED duk_str_unsupported
2330#define DUK_STR_ARRAY_LENGTH_OVER_2G duk_str_array_length_over_2g
2331
2332#if !defined(DUK_SINGLE_FILE)
2333DUK_INTERNAL_DECL const char *duk_str_invalid_context;
7c673cae 2334DUK_INTERNAL_DECL const char *duk_str_push_beyond_alloc_stack;
7c673cae
FG
2335DUK_INTERNAL_DECL const char *duk_str_not_buffer;
2336DUK_INTERNAL_DECL const char *duk_str_unexpected_type;
7c673cae
FG
2337DUK_INTERNAL_DECL const char *duk_str_defaultvalue_coerce_failed;
2338DUK_INTERNAL_DECL const char *duk_str_number_outside_range;
2339DUK_INTERNAL_DECL const char *duk_str_not_object_coercible;
2340DUK_INTERNAL_DECL const char *duk_str_string_too_long;
2341DUK_INTERNAL_DECL const char *duk_str_buffer_too_long;
2342DUK_INTERNAL_DECL const char *duk_str_sprintf_too_long;
2343DUK_INTERNAL_DECL const char *duk_str_alloc_failed;
2344DUK_INTERNAL_DECL const char *duk_str_pop_too_many;
2345DUK_INTERNAL_DECL const char *duk_str_wrong_buffer_type;
7c673cae
FG
2346DUK_INTERNAL_DECL const char *duk_str_encode_failed;
2347DUK_INTERNAL_DECL const char *duk_str_decode_failed;
2348DUK_INTERNAL_DECL const char *duk_str_no_sourcecode;
2349DUK_INTERNAL_DECL const char *duk_str_concat_result_too_long;
2350DUK_INTERNAL_DECL const char *duk_str_unimplemented;
2351DUK_INTERNAL_DECL const char *duk_str_unsupported;
2352DUK_INTERNAL_DECL const char *duk_str_array_length_over_2g;
2353#endif /* !DUK_SINGLE_FILE */
2354
2355#define DUK_STR_FMT_PTR duk_str_fmt_ptr
2356#define DUK_STR_FMT_INVALID_JSON duk_str_fmt_invalid_json
2357#define DUK_STR_JSONDEC_RECLIMIT duk_str_jsondec_reclimit
2358#define DUK_STR_JSONENC_RECLIMIT duk_str_jsonenc_reclimit
2359#define DUK_STR_CYCLIC_INPUT duk_str_cyclic_input
2360
2361#if !defined(DUK_SINGLE_FILE)
2362DUK_INTERNAL_DECL const char *duk_str_fmt_ptr;
2363DUK_INTERNAL_DECL const char *duk_str_fmt_invalid_json;
2364DUK_INTERNAL_DECL const char *duk_str_jsondec_reclimit;
2365DUK_INTERNAL_DECL const char *duk_str_jsonenc_reclimit;
2366DUK_INTERNAL_DECL const char *duk_str_cyclic_input;
2367#endif /* !DUK_SINGLE_FILE */
2368
2369#define DUK_STR_PROXY_REVOKED duk_str_proxy_revoked
7c673cae
FG
2370#define DUK_STR_INVALID_BASE duk_str_invalid_base
2371#define DUK_STR_STRICT_CALLER_READ duk_str_strict_caller_read
2372#define DUK_STR_PROXY_REJECTED duk_str_proxy_rejected
2373#define DUK_STR_INVALID_ARRAY_LENGTH duk_str_invalid_array_length
2374#define DUK_STR_ARRAY_LENGTH_WRITE_FAILED duk_str_array_length_write_failed
2375#define DUK_STR_ARRAY_LENGTH_NOT_WRITABLE duk_str_array_length_not_writable
2376#define DUK_STR_SETTER_UNDEFINED duk_str_setter_undefined
2377#define DUK_STR_REDEFINE_VIRT_PROP duk_str_redefine_virt_prop
2378#define DUK_STR_INVALID_DESCRIPTOR duk_str_invalid_descriptor
2379#define DUK_STR_PROPERTY_IS_VIRTUAL duk_str_property_is_virtual
2380
2381#if !defined(DUK_SINGLE_FILE)
2382DUK_INTERNAL_DECL const char *duk_str_proxy_revoked;
7c673cae
FG
2383DUK_INTERNAL_DECL const char *duk_str_invalid_base;
2384DUK_INTERNAL_DECL const char *duk_str_strict_caller_read;
2385DUK_INTERNAL_DECL const char *duk_str_proxy_rejected;
2386DUK_INTERNAL_DECL const char *duk_str_invalid_array_length;
2387DUK_INTERNAL_DECL const char *duk_str_array_length_write_failed;
2388DUK_INTERNAL_DECL const char *duk_str_array_length_not_writable;
2389DUK_INTERNAL_DECL const char *duk_str_setter_undefined;
2390DUK_INTERNAL_DECL const char *duk_str_redefine_virt_prop;
2391DUK_INTERNAL_DECL const char *duk_str_invalid_descriptor;
2392DUK_INTERNAL_DECL const char *duk_str_property_is_virtual;
2393#endif /* !DUK_SINGLE_FILE */
2394
2395#define DUK_STR_PARSE_ERROR duk_str_parse_error
2396#define DUK_STR_DUPLICATE_LABEL duk_str_duplicate_label
2397#define DUK_STR_INVALID_LABEL duk_str_invalid_label
2398#define DUK_STR_INVALID_ARRAY_LITERAL duk_str_invalid_array_literal
2399#define DUK_STR_INVALID_OBJECT_LITERAL duk_str_invalid_object_literal
2400#define DUK_STR_INVALID_VAR_DECLARATION duk_str_invalid_var_declaration
2401#define DUK_STR_CANNOT_DELETE_IDENTIFIER duk_str_cannot_delete_identifier
2402#define DUK_STR_INVALID_EXPRESSION duk_str_invalid_expression
2403#define DUK_STR_INVALID_LVALUE duk_str_invalid_lvalue
2404#define DUK_STR_EXPECTED_IDENTIFIER duk_str_expected_identifier
2405#define DUK_STR_EMPTY_EXPR_NOT_ALLOWED duk_str_empty_expr_not_allowed
2406#define DUK_STR_INVALID_FOR duk_str_invalid_for
2407#define DUK_STR_INVALID_SWITCH duk_str_invalid_switch
2408#define DUK_STR_INVALID_BREAK_CONT_LABEL duk_str_invalid_break_cont_label
2409#define DUK_STR_INVALID_RETURN duk_str_invalid_return
2410#define DUK_STR_INVALID_TRY duk_str_invalid_try
2411#define DUK_STR_INVALID_THROW duk_str_invalid_throw
2412#define DUK_STR_WITH_IN_STRICT_MODE duk_str_with_in_strict_mode
2413#define DUK_STR_FUNC_STMT_NOT_ALLOWED duk_str_func_stmt_not_allowed
2414#define DUK_STR_UNTERMINATED_STMT duk_str_unterminated_stmt
2415#define DUK_STR_INVALID_ARG_NAME duk_str_invalid_arg_name
2416#define DUK_STR_INVALID_FUNC_NAME duk_str_invalid_func_name
2417#define DUK_STR_INVALID_GETSET_NAME duk_str_invalid_getset_name
2418#define DUK_STR_FUNC_NAME_REQUIRED duk_str_func_name_required
2419
2420#if !defined(DUK_SINGLE_FILE)
2421DUK_INTERNAL_DECL const char *duk_str_parse_error;
2422DUK_INTERNAL_DECL const char *duk_str_duplicate_label;
2423DUK_INTERNAL_DECL const char *duk_str_invalid_label;
2424DUK_INTERNAL_DECL const char *duk_str_invalid_array_literal;
2425DUK_INTERNAL_DECL const char *duk_str_invalid_object_literal;
2426DUK_INTERNAL_DECL const char *duk_str_invalid_var_declaration;
2427DUK_INTERNAL_DECL const char *duk_str_cannot_delete_identifier;
2428DUK_INTERNAL_DECL const char *duk_str_invalid_expression;
2429DUK_INTERNAL_DECL const char *duk_str_invalid_lvalue;
2430DUK_INTERNAL_DECL const char *duk_str_expected_identifier;
2431DUK_INTERNAL_DECL const char *duk_str_empty_expr_not_allowed;
2432DUK_INTERNAL_DECL const char *duk_str_invalid_for;
2433DUK_INTERNAL_DECL const char *duk_str_invalid_switch;
2434DUK_INTERNAL_DECL const char *duk_str_invalid_break_cont_label;
2435DUK_INTERNAL_DECL const char *duk_str_invalid_return;
2436DUK_INTERNAL_DECL const char *duk_str_invalid_try;
2437DUK_INTERNAL_DECL const char *duk_str_invalid_throw;
2438DUK_INTERNAL_DECL const char *duk_str_with_in_strict_mode;
2439DUK_INTERNAL_DECL const char *duk_str_func_stmt_not_allowed;
2440DUK_INTERNAL_DECL const char *duk_str_unterminated_stmt;
2441DUK_INTERNAL_DECL const char *duk_str_invalid_arg_name;
2442DUK_INTERNAL_DECL const char *duk_str_invalid_func_name;
2443DUK_INTERNAL_DECL const char *duk_str_invalid_getset_name;
2444DUK_INTERNAL_DECL const char *duk_str_func_name_required;
2445#endif /* !DUK_SINGLE_FILE */
2446
7c673cae
FG
2447#define DUK_STR_INVALID_QUANTIFIER_NO_ATOM duk_str_invalid_quantifier_no_atom
2448#define DUK_STR_INVALID_QUANTIFIER_VALUES duk_str_invalid_quantifier_values
2449#define DUK_STR_QUANTIFIER_TOO_MANY_COPIES duk_str_quantifier_too_many_copies
2450#define DUK_STR_UNEXPECTED_CLOSING_PAREN duk_str_unexpected_closing_paren
2451#define DUK_STR_UNEXPECTED_END_OF_PATTERN duk_str_unexpected_end_of_pattern
2452#define DUK_STR_UNEXPECTED_REGEXP_TOKEN duk_str_unexpected_regexp_token
2453#define DUK_STR_INVALID_REGEXP_FLAGS duk_str_invalid_regexp_flags
2454#define DUK_STR_INVALID_BACKREFS duk_str_invalid_backrefs
7c673cae
FG
2455
2456#if !defined(DUK_SINGLE_FILE)
2457DUK_INTERNAL_DECL const char *duk_str_invalid_quantifier_no_atom;
2458DUK_INTERNAL_DECL const char *duk_str_invalid_quantifier_values;
2459DUK_INTERNAL_DECL const char *duk_str_quantifier_too_many_copies;
2460DUK_INTERNAL_DECL const char *duk_str_unexpected_closing_paren;
2461DUK_INTERNAL_DECL const char *duk_str_unexpected_end_of_pattern;
2462DUK_INTERNAL_DECL const char *duk_str_unexpected_regexp_token;
2463DUK_INTERNAL_DECL const char *duk_str_invalid_regexp_flags;
2464DUK_INTERNAL_DECL const char *duk_str_invalid_backrefs;
7c673cae
FG
2465#endif /* !DUK_SINGLE_FILE */
2466
2467#define DUK_STR_VALSTACK_LIMIT duk_str_valstack_limit
2468#define DUK_STR_CALLSTACK_LIMIT duk_str_callstack_limit
2469#define DUK_STR_CATCHSTACK_LIMIT duk_str_catchstack_limit
7c673cae
FG
2470#define DUK_STR_PROTOTYPE_CHAIN_LIMIT duk_str_prototype_chain_limit
2471#define DUK_STR_BOUND_CHAIN_LIMIT duk_str_bound_chain_limit
2472#define DUK_STR_C_CALLSTACK_LIMIT duk_str_c_callstack_limit
2473#define DUK_STR_COMPILER_RECURSION_LIMIT duk_str_compiler_recursion_limit
2474#define DUK_STR_BYTECODE_LIMIT duk_str_bytecode_limit
2475#define DUK_STR_REG_LIMIT duk_str_reg_limit
2476#define DUK_STR_TEMP_LIMIT duk_str_temp_limit
2477#define DUK_STR_CONST_LIMIT duk_str_const_limit
2478#define DUK_STR_FUNC_LIMIT duk_str_func_limit
2479#define DUK_STR_REGEXP_COMPILER_RECURSION_LIMIT duk_str_regexp_compiler_recursion_limit
2480#define DUK_STR_REGEXP_EXECUTOR_RECURSION_LIMIT duk_str_regexp_executor_recursion_limit
2481#define DUK_STR_REGEXP_EXECUTOR_STEP_LIMIT duk_str_regexp_executor_step_limit
2482
2483#if !defined(DUK_SINGLE_FILE)
2484DUK_INTERNAL_DECL const char *duk_str_valstack_limit;
2485DUK_INTERNAL_DECL const char *duk_str_callstack_limit;
2486DUK_INTERNAL_DECL const char *duk_str_catchstack_limit;
7c673cae
FG
2487DUK_INTERNAL_DECL const char *duk_str_prototype_chain_limit;
2488DUK_INTERNAL_DECL const char *duk_str_bound_chain_limit;
2489DUK_INTERNAL_DECL const char *duk_str_c_callstack_limit;
2490DUK_INTERNAL_DECL const char *duk_str_compiler_recursion_limit;
2491DUK_INTERNAL_DECL const char *duk_str_bytecode_limit;
2492DUK_INTERNAL_DECL const char *duk_str_reg_limit;
2493DUK_INTERNAL_DECL const char *duk_str_temp_limit;
2494DUK_INTERNAL_DECL const char *duk_str_const_limit;
2495DUK_INTERNAL_DECL const char *duk_str_func_limit;
2496DUK_INTERNAL_DECL const char *duk_str_regexp_compiler_recursion_limit;
2497DUK_INTERNAL_DECL const char *duk_str_regexp_executor_recursion_limit;
2498DUK_INTERNAL_DECL const char *duk_str_regexp_executor_step_limit;
2499#endif /* !DUK_SINGLE_FILE */
2500
7c673cae
FG
2501#if !defined(DUK_SINGLE_FILE)
2502DUK_INTERNAL_DECL const char *duk_str_anon;
7c673cae
FG
2503#endif /* !DUK_SINGLE_FILE */
2504
2505#endif /* DUK_ERRMSG_H_INCLUDED */
7c673cae
FG
2506/*
2507 * Ecmascript bytecode
2508 */
2509
2510#ifndef DUK_JS_BYTECODE_H_INCLUDED
2511#define DUK_JS_BYTECODE_H_INCLUDED
2512
2513/*
2514 * Logical instruction layout
2515 * ==========================
2516 *
2517 * !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! !
2518 * !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!
2519 * +---------------------------------------------------+-----------+
2520 * ! C ! B ! A ! OP !
2521 * +---------------------------------------------------+-----------+
2522 *
2523 * OP (6 bits): opcode (DUK_OP_*), access should be fastest
2524 * A (8 bits): typically a target register number
2525 * B (9 bits): typically first source register/constant number
2526 * C (9 bits): typically second source register/constant number
2527 *
2528 * Some instructions combine BC or ABC together for larger parameter values.
2529 * Signed integers (e.g. jump offsets) are encoded as unsigned, with an opcode
2530 * specific bias. B and C may denote a register or a constant, see
2531 * DUK_BC_ISREG() and DUK_BC_ISCONST().
2532 *
2533 * Note: macro naming is a bit misleading, e.g. "ABC" in macro name but
2534 * the field layout is logically "CBA".
2535 */
2536
2537typedef duk_uint32_t duk_instr_t;
2538
2539#define DUK_DEC_OP(x) ((x) & 0x3fUL)
2540#define DUK_DEC_A(x) (((x) >> 6) & 0xffUL)
2541#define DUK_DEC_B(x) (((x) >> 14) & 0x1ffUL)
2542#define DUK_DEC_C(x) (((x) >> 23) & 0x1ffUL)
2543#define DUK_DEC_BC(x) (((x) >> 14) & 0x3ffffUL)
2544#define DUK_DEC_ABC(x) (((x) >> 6) & 0x3ffffffUL)
2545
2546#define DUK_ENC_OP(op) ((duk_instr_t) (op))
2547#define DUK_ENC_OP_ABC(op,abc) ((duk_instr_t) ( \
2548 (((duk_instr_t) (abc)) << 6) | \
2549 ((duk_instr_t) (op)) \
2550 ))
2551#define DUK_ENC_OP_A_BC(op,a,bc) ((duk_instr_t) ( \
2552 (((duk_instr_t) (bc)) << 14) | \
2553 (((duk_instr_t) (a)) << 6) | \
2554 ((duk_instr_t) (op)) \
2555 ))
2556#define DUK_ENC_OP_A_B_C(op,a,b,c) ((duk_instr_t) ( \
2557 (((duk_instr_t) (c)) << 23) | \
2558 (((duk_instr_t) (b)) << 14) | \
2559 (((duk_instr_t) (a)) << 6) | \
2560 ((duk_instr_t) (op)) \
2561 ))
2562#define DUK_ENC_OP_A_B(op,a,b) DUK_ENC_OP_A_B_C(op,a,b,0)
2563#define DUK_ENC_OP_A(op,a) DUK_ENC_OP_A_B_C(op,a,0,0)
2564
2565/* Constants should be signed so that signed arithmetic involving them
2566 * won't cause values to be coerced accidentally to unsigned.
2567 */
2568#define DUK_BC_OP_MIN 0
2569#define DUK_BC_OP_MAX 0x3fL
2570#define DUK_BC_A_MIN 0
2571#define DUK_BC_A_MAX 0xffL
2572#define DUK_BC_B_MIN 0
2573#define DUK_BC_B_MAX 0x1ffL
2574#define DUK_BC_C_MIN 0
2575#define DUK_BC_C_MAX 0x1ffL
2576#define DUK_BC_BC_MIN 0
2577#define DUK_BC_BC_MAX 0x3ffffL
2578#define DUK_BC_ABC_MIN 0
2579#define DUK_BC_ABC_MAX 0x3ffffffL
2580#define DUK_BC_EXTRAOP_MIN DUK_BC_A_MIN
2581#define DUK_BC_EXTRAOP_MAX DUK_BC_A_MAX
2582
2583#define DUK_OP_LDREG 0
2584#define DUK_OP_STREG 1
2585#define DUK_OP_LDCONST 2
2586#define DUK_OP_LDINT 3
2587#define DUK_OP_LDINTX 4
2588#define DUK_OP_MPUTOBJ 5
2589#define DUK_OP_MPUTOBJI 6
2590#define DUK_OP_MPUTARR 7
2591#define DUK_OP_MPUTARRI 8
2592#define DUK_OP_NEW 9
2593#define DUK_OP_NEWI 10
2594#define DUK_OP_REGEXP 11
2595#define DUK_OP_CSREG 12
2596#define DUK_OP_CSREGI 13
2597#define DUK_OP_GETVAR 14
2598#define DUK_OP_PUTVAR 15
2599#define DUK_OP_DECLVAR 16
2600#define DUK_OP_DELVAR 17
2601#define DUK_OP_CSVAR 18
2602#define DUK_OP_CSVARI 19
2603#define DUK_OP_CLOSURE 20
2604#define DUK_OP_GETPROP 21
2605#define DUK_OP_PUTPROP 22
2606#define DUK_OP_DELPROP 23
2607#define DUK_OP_CSPROP 24
2608#define DUK_OP_CSPROPI 25
2609#define DUK_OP_ADD 26
2610#define DUK_OP_SUB 27
2611#define DUK_OP_MUL 28
2612#define DUK_OP_DIV 29
2613#define DUK_OP_MOD 30
2614#define DUK_OP_BAND 31
2615#define DUK_OP_BOR 32
2616#define DUK_OP_BXOR 33
2617#define DUK_OP_BASL 34
2618#define DUK_OP_BLSR 35
2619#define DUK_OP_BASR 36
2620#define DUK_OP_EQ 37
2621#define DUK_OP_NEQ 38
2622#define DUK_OP_SEQ 39
2623#define DUK_OP_SNEQ 40
2624#define DUK_OP_GT 41
2625#define DUK_OP_GE 42
2626#define DUK_OP_LT 43
2627#define DUK_OP_LE 44
2628#define DUK_OP_IF 45
2629#define DUK_OP_JUMP 46
2630#define DUK_OP_RETURN 47
2631#define DUK_OP_CALL 48
2632#define DUK_OP_CALLI 49
2633#define DUK_OP_TRYCATCH 50
2634#define DUK_OP_EXTRA 51
2635#define DUK_OP_PREINCR 52 /* pre/post opcode values have constraints, */
2636#define DUK_OP_PREDECR 53 /* see duk_js_executor.c */
2637#define DUK_OP_POSTINCR 54
2638#define DUK_OP_POSTDECR 55
2639#define DUK_OP_PREINCV 56
2640#define DUK_OP_PREDECV 57
2641#define DUK_OP_POSTINCV 58
2642#define DUK_OP_POSTDECV 59
2643#define DUK_OP_PREINCP 60
2644#define DUK_OP_PREDECP 61
2645#define DUK_OP_POSTINCP 62
2646#define DUK_OP_POSTDECP 63
2647#define DUK_OP_NONE 64 /* dummy value used as marker */
2648
2649/* DUK_OP_EXTRA, sub-operation in A */
2650#define DUK_EXTRAOP_NOP 0
2651#define DUK_EXTRAOP_INVALID 1
2652#define DUK_EXTRAOP_LDTHIS 2
2653#define DUK_EXTRAOP_LDUNDEF 3
2654#define DUK_EXTRAOP_LDNULL 4
2655#define DUK_EXTRAOP_LDTRUE 5
2656#define DUK_EXTRAOP_LDFALSE 6
2657#define DUK_EXTRAOP_NEWOBJ 7
2658#define DUK_EXTRAOP_NEWARR 8
2659#define DUK_EXTRAOP_SETALEN 9
2660#define DUK_EXTRAOP_TYPEOF 10
2661#define DUK_EXTRAOP_TYPEOFID 11
2662#define DUK_EXTRAOP_INITENUM 12
2663#define DUK_EXTRAOP_NEXTENUM 13
2664#define DUK_EXTRAOP_INITSET 14
2665#define DUK_EXTRAOP_INITSETI 15
2666#define DUK_EXTRAOP_INITGET 16
2667#define DUK_EXTRAOP_INITGETI 17
2668#define DUK_EXTRAOP_ENDTRY 18
2669#define DUK_EXTRAOP_ENDCATCH 19
2670#define DUK_EXTRAOP_ENDFIN 20
2671#define DUK_EXTRAOP_THROW 21
2672#define DUK_EXTRAOP_INVLHS 22
2673#define DUK_EXTRAOP_UNM 23
2674#define DUK_EXTRAOP_UNP 24
2675#define DUK_EXTRAOP_DEBUGGER 25
2676#define DUK_EXTRAOP_BREAK 26
2677#define DUK_EXTRAOP_CONTINUE 27
2678#define DUK_EXTRAOP_BNOT 28
2679#define DUK_EXTRAOP_LNOT 29
2680#define DUK_EXTRAOP_INSTOF 30
2681#define DUK_EXTRAOP_IN 31
2682#define DUK_EXTRAOP_LABEL 32
2683#define DUK_EXTRAOP_ENDLABEL 33
2684
2685/* DUK_OP_CALL flags in A */
2686#define DUK_BC_CALL_FLAG_TAILCALL (1 << 0)
2687#define DUK_BC_CALL_FLAG_EVALCALL (1 << 1)
2688
2689/* DUK_OP_TRYCATCH flags in A */
2690#define DUK_BC_TRYCATCH_FLAG_HAVE_CATCH (1 << 0)
2691#define DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY (1 << 1)
2692#define DUK_BC_TRYCATCH_FLAG_CATCH_BINDING (1 << 2)
2693#define DUK_BC_TRYCATCH_FLAG_WITH_BINDING (1 << 3)
2694
2695/* DUK_OP_RETURN flags in A */
11fdf7f2 2696#define DUK_BC_RETURN_FLAG_HAVE_RETVAL (1 << 0)
7c673cae
FG
2697
2698/* DUK_OP_DECLVAR flags in A; bottom bits are reserved for propdesc flags (DUK_PROPDESC_FLAG_XXX) */
2699#define DUK_BC_DECLVAR_FLAG_UNDEF_VALUE (1 << 4) /* use 'undefined' for value automatically */
2700#define DUK_BC_DECLVAR_FLAG_FUNC_DECL (1 << 5) /* function declaration */
2701
2702/* misc constants and helper macros */
2703#define DUK_BC_REGLIMIT 256 /* if B/C is >= this value, refers to a const */
2704#define DUK_BC_ISREG(x) ((x) < DUK_BC_REGLIMIT)
2705#define DUK_BC_ISCONST(x) ((x) >= DUK_BC_REGLIMIT)
2706#define DUK_BC_LDINT_BIAS (1L << 17)
2707#define DUK_BC_LDINTX_SHIFT 18
2708#define DUK_BC_JUMP_BIAS (1L << 25)
2709
2710#endif /* DUK_JS_BYTECODE_H_INCLUDED */
7c673cae
FG
2711/*
2712 * Lexer defines.
2713 */
2714
2715#ifndef DUK_LEXER_H_INCLUDED
2716#define DUK_LEXER_H_INCLUDED
2717
2718typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepoint_t r2, duk_bool_t direct);
2719
2720/*
2721 * A token is interpreted as any possible production of InputElementDiv
2722 * and InputElementRegExp, see E5 Section 7 in its entirety. Note that
2723 * the E5 "Token" production does not cover all actual tokens of the
2724 * language (which is explicitly stated in the specification, Section 7.5).
2725 * Null and boolean literals are defined as part of both ReservedWord
2726 * (E5 Section 7.6.1) and Literal (E5 Section 7.8) productions. Here,
2727 * null and boolean values have literal tokens, and are not reserved
2728 * words.
2729 *
2730 * Decimal literal negative/positive sign is -not- part of DUK_TOK_NUMBER.
2731 * The number tokens always have a non-negative value. The unary minus
2732 * operator in "-1.0" is optimized during compilation to yield a single
2733 * negative constant.
2734 *
2735 * Token numbering is free except that reserved words are required to be
2736 * in a continuous range and in a particular order. See genstrings.py.
2737 */
2738
2739#define DUK_LEXER_INITCTX(ctx) duk_lexer_initctx((ctx))
2740
2741#define DUK_LEXER_SETPOINT(ctx,pt) duk_lexer_setpoint((ctx), (pt))
2742
2743#define DUK_LEXER_GETPOINT(ctx,pt) do { (pt)->offset = (ctx)->window[0].offset; \
2744 (pt)->line = (ctx)->window[0].line; } while (0)
2745
2746/* currently 6 characters of lookup are actually needed (duk_lexer.c) */
2747#define DUK_LEXER_WINDOW_SIZE 6
2748#if defined(DUK_USE_LEXER_SLIDING_WINDOW)
2749#define DUK_LEXER_BUFFER_SIZE 64
2750#endif
2751
2752#define DUK_TOK_MINVAL 0
2753
2754/* returned after EOF (infinite amount) */
2755#define DUK_TOK_EOF 0
2756
2757/* identifier names (E5 Section 7.6) */
2758#define DUK_TOK_IDENTIFIER 1
2759
2760/* reserved words: keywords */
2761#define DUK_TOK_START_RESERVED 2
2762#define DUK_TOK_BREAK 2
2763#define DUK_TOK_CASE 3
2764#define DUK_TOK_CATCH 4
2765#define DUK_TOK_CONTINUE 5
2766#define DUK_TOK_DEBUGGER 6
2767#define DUK_TOK_DEFAULT 7
2768#define DUK_TOK_DELETE 8
2769#define DUK_TOK_DO 9
2770#define DUK_TOK_ELSE 10
2771#define DUK_TOK_FINALLY 11
2772#define DUK_TOK_FOR 12
2773#define DUK_TOK_FUNCTION 13
2774#define DUK_TOK_IF 14
2775#define DUK_TOK_IN 15
2776#define DUK_TOK_INSTANCEOF 16
2777#define DUK_TOK_NEW 17
2778#define DUK_TOK_RETURN 18
2779#define DUK_TOK_SWITCH 19
2780#define DUK_TOK_THIS 20
2781#define DUK_TOK_THROW 21
2782#define DUK_TOK_TRY 22
2783#define DUK_TOK_TYPEOF 23
2784#define DUK_TOK_VAR 24
11fdf7f2
TL
2785#define DUK_TOK_CONST 25
2786#define DUK_TOK_VOID 26
2787#define DUK_TOK_WHILE 27
2788#define DUK_TOK_WITH 28
7c673cae
FG
2789
2790/* reserved words: future reserved words */
11fdf7f2 2791#define DUK_TOK_CLASS 29
7c673cae
FG
2792#define DUK_TOK_ENUM 30
2793#define DUK_TOK_EXPORT 31
2794#define DUK_TOK_EXTENDS 32
2795#define DUK_TOK_IMPORT 33
2796#define DUK_TOK_SUPER 34
2797
2798/* "null", "true", and "false" are always reserved words.
2799 * Note that "get" and "set" are not!
2800 */
2801#define DUK_TOK_NULL 35
2802#define DUK_TOK_TRUE 36
2803#define DUK_TOK_FALSE 37
2804
2805/* reserved words: additional future reserved words in strict mode */
2806#define DUK_TOK_START_STRICT_RESERVED 38 /* inclusive */
2807#define DUK_TOK_IMPLEMENTS 38
2808#define DUK_TOK_INTERFACE 39
2809#define DUK_TOK_LET 40
2810#define DUK_TOK_PACKAGE 41
2811#define DUK_TOK_PRIVATE 42
2812#define DUK_TOK_PROTECTED 43
2813#define DUK_TOK_PUBLIC 44
2814#define DUK_TOK_STATIC 45
2815#define DUK_TOK_YIELD 46
2816
2817#define DUK_TOK_END_RESERVED 47 /* exclusive */
2818
2819/* "get" and "set" are tokens but NOT ReservedWords. They are currently
2820 * parsed and identifiers and these defines are actually now unused.
2821 */
2822#define DUK_TOK_GET 47
2823#define DUK_TOK_SET 48
2824
2825/* punctuators (unlike the spec, also includes "/" and "/=") */
2826#define DUK_TOK_LCURLY 49
2827#define DUK_TOK_RCURLY 50
2828#define DUK_TOK_LBRACKET 51
2829#define DUK_TOK_RBRACKET 52
2830#define DUK_TOK_LPAREN 53
2831#define DUK_TOK_RPAREN 54
2832#define DUK_TOK_PERIOD 55
2833#define DUK_TOK_SEMICOLON 56
2834#define DUK_TOK_COMMA 57
2835#define DUK_TOK_LT 58
2836#define DUK_TOK_GT 59
2837#define DUK_TOK_LE 60
2838#define DUK_TOK_GE 61
2839#define DUK_TOK_EQ 62
2840#define DUK_TOK_NEQ 63
2841#define DUK_TOK_SEQ 64
2842#define DUK_TOK_SNEQ 65
2843#define DUK_TOK_ADD 66
2844#define DUK_TOK_SUB 67
2845#define DUK_TOK_MUL 68
2846#define DUK_TOK_DIV 69
2847#define DUK_TOK_MOD 70
2848#define DUK_TOK_INCREMENT 71
2849#define DUK_TOK_DECREMENT 72
2850#define DUK_TOK_ALSHIFT 73 /* named "arithmetic" because result is signed */
2851#define DUK_TOK_ARSHIFT 74
2852#define DUK_TOK_RSHIFT 75
2853#define DUK_TOK_BAND 76
2854#define DUK_TOK_BOR 77
2855#define DUK_TOK_BXOR 78
2856#define DUK_TOK_LNOT 79
2857#define DUK_TOK_BNOT 80
2858#define DUK_TOK_LAND 81
2859#define DUK_TOK_LOR 82
2860#define DUK_TOK_QUESTION 83
2861#define DUK_TOK_COLON 84
2862#define DUK_TOK_EQUALSIGN 85
2863#define DUK_TOK_ADD_EQ 86
2864#define DUK_TOK_SUB_EQ 87
2865#define DUK_TOK_MUL_EQ 88
2866#define DUK_TOK_DIV_EQ 89
2867#define DUK_TOK_MOD_EQ 90
2868#define DUK_TOK_ALSHIFT_EQ 91
2869#define DUK_TOK_ARSHIFT_EQ 92
2870#define DUK_TOK_RSHIFT_EQ 93
2871#define DUK_TOK_BAND_EQ 94
2872#define DUK_TOK_BOR_EQ 95
2873#define DUK_TOK_BXOR_EQ 96
2874
2875/* literals (E5 Section 7.8), except null, true, false, which are treated
2876 * like reserved words (above).
2877 */
2878#define DUK_TOK_NUMBER 97
2879#define DUK_TOK_STRING 98
2880#define DUK_TOK_REGEXP 99
2881
2882#define DUK_TOK_MAXVAL 99 /* inclusive */
2883
2884/* Convert heap string index to a token (reserved words) */
2885#define DUK_STRIDX_TO_TOK(x) ((x) - DUK_STRIDX_START_RESERVED + DUK_TOK_START_RESERVED)
2886
2887/* Sanity check */
2888#if (DUK_TOK_MAXVAL > 255)
2889#error DUK_TOK_MAXVAL too large, code assumes it fits into 8 bits
2890#endif
2891
2892/* Sanity checks for string and token defines */
2893#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_BREAK) != DUK_TOK_BREAK)
2894#error mismatch in token defines
2895#endif
2896#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CASE) != DUK_TOK_CASE)
2897#error mismatch in token defines
2898#endif
2899#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CATCH) != DUK_TOK_CATCH)
2900#error mismatch in token defines
2901#endif
2902#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CONTINUE) != DUK_TOK_CONTINUE)
2903#error mismatch in token defines
2904#endif
2905#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DEBUGGER) != DUK_TOK_DEBUGGER)
2906#error mismatch in token defines
2907#endif
2908#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DEFAULT) != DUK_TOK_DEFAULT)
2909#error mismatch in token defines
2910#endif
2911#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DELETE) != DUK_TOK_DELETE)
2912#error mismatch in token defines
2913#endif
2914#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DO) != DUK_TOK_DO)
2915#error mismatch in token defines
2916#endif
2917#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_ELSE) != DUK_TOK_ELSE)
2918#error mismatch in token defines
2919#endif
2920#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FINALLY) != DUK_TOK_FINALLY)
2921#error mismatch in token defines
2922#endif
2923#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FOR) != DUK_TOK_FOR)
2924#error mismatch in token defines
2925#endif
2926#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LC_FUNCTION) != DUK_TOK_FUNCTION)
2927#error mismatch in token defines
2928#endif
2929#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IF) != DUK_TOK_IF)
2930#error mismatch in token defines
2931#endif
2932#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IN) != DUK_TOK_IN)
2933#error mismatch in token defines
2934#endif
2935#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_INSTANCEOF) != DUK_TOK_INSTANCEOF)
2936#error mismatch in token defines
2937#endif
2938#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_NEW) != DUK_TOK_NEW)
2939#error mismatch in token defines
2940#endif
2941#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_RETURN) != DUK_TOK_RETURN)
2942#error mismatch in token defines
2943#endif
2944#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_SWITCH) != DUK_TOK_SWITCH)
2945#error mismatch in token defines
2946#endif
2947#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_THIS) != DUK_TOK_THIS)
2948#error mismatch in token defines
2949#endif
2950#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_THROW) != DUK_TOK_THROW)
2951#error mismatch in token defines
2952#endif
2953#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TRY) != DUK_TOK_TRY)
2954#error mismatch in token defines
2955#endif
2956#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TYPEOF) != DUK_TOK_TYPEOF)
2957#error mismatch in token defines
2958#endif
2959#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_VAR) != DUK_TOK_VAR)
2960#error mismatch in token defines
2961#endif
2962#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_VOID) != DUK_TOK_VOID)
2963#error mismatch in token defines
2964#endif
2965#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_WHILE) != DUK_TOK_WHILE)
2966#error mismatch in token defines
2967#endif
2968#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_WITH) != DUK_TOK_WITH)
2969#error mismatch in token defines
2970#endif
2971#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CLASS) != DUK_TOK_CLASS)
2972#error mismatch in token defines
2973#endif
2974#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CONST) != DUK_TOK_CONST)
2975#error mismatch in token defines
2976#endif
2977#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_ENUM) != DUK_TOK_ENUM)
2978#error mismatch in token defines
2979#endif
2980#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_EXPORT) != DUK_TOK_EXPORT)
2981#error mismatch in token defines
2982#endif
2983#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_EXTENDS) != DUK_TOK_EXTENDS)
2984#error mismatch in token defines
2985#endif
2986#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IMPORT) != DUK_TOK_IMPORT)
2987#error mismatch in token defines
2988#endif
2989#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_SUPER) != DUK_TOK_SUPER)
2990#error mismatch in token defines
2991#endif
2992#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LC_NULL) != DUK_TOK_NULL)
2993#error mismatch in token defines
2994#endif
2995#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TRUE) != DUK_TOK_TRUE)
2996#error mismatch in token defines
2997#endif
2998#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FALSE) != DUK_TOK_FALSE)
2999#error mismatch in token defines
3000#endif
3001#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IMPLEMENTS) != DUK_TOK_IMPLEMENTS)
3002#error mismatch in token defines
3003#endif
3004#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_INTERFACE) != DUK_TOK_INTERFACE)
3005#error mismatch in token defines
3006#endif
3007#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LET) != DUK_TOK_LET)
3008#error mismatch in token defines
3009#endif
3010#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PACKAGE) != DUK_TOK_PACKAGE)
3011#error mismatch in token defines
3012#endif
3013#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PRIVATE) != DUK_TOK_PRIVATE)
3014#error mismatch in token defines
3015#endif
3016#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PROTECTED) != DUK_TOK_PROTECTED)
3017#error mismatch in token defines
3018#endif
3019#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PUBLIC) != DUK_TOK_PUBLIC)
3020#error mismatch in token defines
3021#endif
3022#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_STATIC) != DUK_TOK_STATIC)
3023#error mismatch in token defines
3024#endif
3025#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_YIELD) != DUK_TOK_YIELD)
3026#error mismatch in token defines
3027#endif
3028
3029/* Regexp tokens */
3030#define DUK_RETOK_EOF 0
3031#define DUK_RETOK_DISJUNCTION 1
3032#define DUK_RETOK_QUANTIFIER 2
3033#define DUK_RETOK_ASSERT_START 3
3034#define DUK_RETOK_ASSERT_END 4
3035#define DUK_RETOK_ASSERT_WORD_BOUNDARY 5
3036#define DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY 6
3037#define DUK_RETOK_ASSERT_START_POS_LOOKAHEAD 7
3038#define DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD 8
3039#define DUK_RETOK_ATOM_PERIOD 9
3040#define DUK_RETOK_ATOM_CHAR 10
3041#define DUK_RETOK_ATOM_DIGIT 11
3042#define DUK_RETOK_ATOM_NOT_DIGIT 12
3043#define DUK_RETOK_ATOM_WHITE 13
3044#define DUK_RETOK_ATOM_NOT_WHITE 14
3045#define DUK_RETOK_ATOM_WORD_CHAR 15
3046#define DUK_RETOK_ATOM_NOT_WORD_CHAR 16
3047#define DUK_RETOK_ATOM_BACKREFERENCE 17
3048#define DUK_RETOK_ATOM_START_CAPTURE_GROUP 18
3049#define DUK_RETOK_ATOM_START_NONCAPTURE_GROUP 19
3050#define DUK_RETOK_ATOM_START_CHARCLASS 20
3051#define DUK_RETOK_ATOM_START_CHARCLASS_INVERTED 21
3052#define DUK_RETOK_ATOM_END_GROUP 22
3053
3054/* Constants for duk_lexer_ctx.buf. */
3055#define DUK_LEXER_TEMP_BUF_LIMIT 256
3056
3057/* A token value. Can be memcpy()'d, but note that slot1/slot2 values are on the valstack.
3058 * Some fields (like num, str1, str2) are only valid for specific token types and may have
3059 * stale values otherwise.
3060 */
3061struct duk_token {
3062 duk_small_int_t t; /* token type (with reserved word identification) */
3063 duk_small_int_t t_nores; /* token type (with reserved words as DUK_TOK_IDENTIFER) */
3064 duk_double_t num; /* numeric value of token */
3065 duk_hstring *str1; /* string 1 of token (borrowed, stored to ctx->slot1_idx) */
3066 duk_hstring *str2; /* string 2 of token (borrowed, stored to ctx->slot2_idx) */
3067 duk_size_t start_offset; /* start byte offset of token in lexer input */
3068 duk_int_t start_line; /* start line of token (first char) */
3069 duk_int_t num_escapes; /* number of escapes and line continuations (for directive prologue) */
3070 duk_bool_t lineterm; /* token was preceded by a lineterm */
3071 duk_bool_t allow_auto_semi; /* token allows automatic semicolon insertion (eof or preceded by newline) */
3072};
3073
3074#define DUK_RE_QUANTIFIER_INFINITE ((duk_uint32_t) 0xffffffffUL)
3075
3076/* A regexp token value. */
3077struct duk_re_token {
3078 duk_small_int_t t; /* token type */
3079 duk_small_int_t greedy;
3080 duk_uint_fast32_t num; /* numeric value (character, count) */
3081 duk_uint_fast32_t qmin;
3082 duk_uint_fast32_t qmax;
3083};
3084
3085/* A structure for 'snapshotting' a point for rewinding */
3086struct duk_lexer_point {
3087 duk_size_t offset;
3088 duk_int_t line;
3089};
3090
3091/* Lexer codepoint with additional info like offset/line number */
3092struct duk_lexer_codepoint {
3093 duk_codepoint_t codepoint;
3094 duk_size_t offset;
3095 duk_int_t line;
3096};
3097
3098/* Lexer context. Same context is used for Ecmascript and Regexp parsing. */
3099struct duk_lexer_ctx {
3100#if defined(DUK_USE_LEXER_SLIDING_WINDOW)
3101 duk_lexer_codepoint *window; /* unicode code points, window[0] is always next, points to 'buffer' */
3102 duk_lexer_codepoint buffer[DUK_LEXER_BUFFER_SIZE];
3103#else
3104 duk_lexer_codepoint window[DUK_LEXER_WINDOW_SIZE]; /* unicode code points, window[0] is always next */
3105#endif
3106
3107 duk_hthread *thr; /* thread; minimizes argument passing */
3108
3109 const duk_uint8_t *input; /* input string (may be a user pointer) */
3110 duk_size_t input_length; /* input byte length */
3111 duk_size_t input_offset; /* input offset for window leading edge (not window[0]) */
3112 duk_int_t input_line; /* input linenumber at input_offset (not window[0]), init to 1 */
3113
3114 duk_idx_t slot1_idx; /* valstack slot for 1st token value */
3115 duk_idx_t slot2_idx; /* valstack slot for 2nd token value */
3116 duk_idx_t buf_idx; /* valstack slot for temp buffer */
3117 duk_hbuffer_dynamic *buf; /* temp accumulation buffer */
3118 duk_bufwriter_ctx bw; /* bufwriter for temp accumulation */
3119
3120 duk_int_t token_count; /* number of tokens parsed */
3121 duk_int_t token_limit; /* maximum token count before error (sanity backstop) */
3122};
3123
3124/*
3125 * Prototypes
3126 */
3127
3128DUK_INTERNAL_DECL void duk_lexer_initctx(duk_lexer_ctx *lex_ctx);
3129
3130DUK_INTERNAL_DECL void duk_lexer_setpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt);
3131
3132DUK_INTERNAL_DECL
3133void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
3134 duk_token *out_token,
3135 duk_bool_t strict_mode,
3136 duk_bool_t regexp_mode);
3137#ifdef DUK_USE_REGEXP_SUPPORT
3138DUK_INTERNAL_DECL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token *out_token);
3139DUK_INTERNAL_DECL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range_callback gen_range, void *userdata);
3140#endif /* DUK_USE_REGEXP_SUPPORT */
3141
3142#endif /* DUK_LEXER_H_INCLUDED */
7c673cae
FG
3143/*
3144 * Ecmascript compiler.
3145 */
3146
3147#ifndef DUK_JS_COMPILER_H_INCLUDED
3148#define DUK_JS_COMPILER_H_INCLUDED
3149
3150/* ecmascript compiler limits */
3151#define DUK_COMPILER_TOKEN_LIMIT 100000000L /* 1e8: protects against deeply nested inner functions */
3152
3153/* maximum loopcount for peephole optimization */
3154#define DUK_COMPILER_PEEPHOLE_MAXITER 3
3155
3156/* maximum bytecode length in instructions */
3157#define DUK_COMPILER_MAX_BYTECODE_LENGTH (256L * 1024L * 1024L) /* 1 GB */
3158
3159/*
3160 * Compiler intermediate values
3161 *
3162 * Intermediate values describe either plain values (e.g. strings or
3163 * numbers) or binary operations which have not yet been coerced into
3164 * either a left-hand-side or right-hand-side role (e.g. object property).
3165 */
3166
3167#define DUK_IVAL_NONE 0 /* no value */
3168#define DUK_IVAL_PLAIN 1 /* register, constant, or value */
3169#define DUK_IVAL_ARITH 2 /* binary arithmetic; DUK_OP_ADD, DUK_OP_EQ, other binary ops */
3170#define DUK_IVAL_ARITH_EXTRAOP 3 /* binary arithmetic using extraops; DUK_EXTRAOP_INSTOF etc */
3171#define DUK_IVAL_PROP 4 /* property access */
3172#define DUK_IVAL_VAR 5 /* variable access */
3173
3174#define DUK_ISPEC_NONE 0 /* no value */
3175#define DUK_ISPEC_VALUE 1 /* value resides in 'valstack_idx' */
3176#define DUK_ISPEC_REGCONST 2 /* value resides in a register or constant */
3177
3178/* bit mask which indicates that a regconst is a constant instead of a register */
3179#define DUK_JS_CONST_MARKER 0x80000000UL
3180
3181/* type to represent a reg/const reference during compilation */
3182typedef duk_uint32_t duk_regconst_t;
3183
3184/* type to represent a straight register reference, with <0 indicating none */
3185typedef duk_int32_t duk_reg_t;
3186
3187typedef struct {
3188 duk_small_uint_t t; /* DUK_ISPEC_XXX */
3189 duk_regconst_t regconst;
3190 duk_idx_t valstack_idx; /* always set; points to a reserved valstack slot */
3191} duk_ispec;
3192
3193typedef struct {
3194 /*
3195 * PLAIN: x1
3196 * ARITH: x1 <op> x2
3197 * PROP: x1.x2
3198 * VAR: x1 (name)
3199 */
3200
3201 /* XXX: can be optimized for smaller footprint esp. on 32-bit environments */
3202 duk_small_uint_t t; /* DUK_IVAL_XXX */
3203 duk_small_uint_t op; /* bytecode opcode (or extraop) for binary ops */
3204 duk_ispec x1;
3205 duk_ispec x2;
3206} duk_ivalue;
3207
3208/*
3209 * Bytecode instruction representation during compilation
3210 *
3211 * Contains the actual instruction and (optionally) debug info.
3212 */
3213
3214struct duk_compiler_instr {
3215 duk_instr_t ins;
3216#if defined(DUK_USE_PC2LINE)
3217 duk_uint32_t line;
3218#endif
3219};
3220
3221/*
3222 * Compiler state
3223 */
3224
3225#define DUK_LABEL_FLAG_ALLOW_BREAK (1 << 0)
3226#define DUK_LABEL_FLAG_ALLOW_CONTINUE (1 << 1)
3227
3228#define DUK_DECL_TYPE_VAR 0
3229#define DUK_DECL_TYPE_FUNC 1
3230
3231/* XXX: optimize to 16 bytes */
3232typedef struct {
3233 duk_small_uint_t flags;
3234 duk_int_t label_id; /* numeric label_id (-1 reserved as marker) */
3235 duk_hstring *h_label; /* borrowed label name */
3236 duk_int_t catch_depth; /* catch depth at point of definition */
3237 duk_int_t pc_label; /* pc of label statement:
3238 * pc+1: break jump site
3239 * pc+2: continue jump site
3240 */
3241
3242 /* Fast jumps (which avoid longjmp) jump directly to the jump sites
3243 * which are always known even while the iteration/switch statement
3244 * is still being parsed. A final peephole pass "straightens out"
3245 * the jumps.
3246 */
3247} duk_labelinfo;
3248
3249/* Compiling state of one function, eventually converted to duk_hcompiledfunction */
3250struct duk_compiler_func {
3251 /* These pointers are at the start of the struct so that they pack
3252 * nicely. Mixing pointers and integer values is bad on some
3253 * platforms (e.g. if int is 32 bits and pointers are 64 bits).
3254 */
3255
3256 duk_bufwriter_ctx bw_code; /* bufwriter for code */
3257
3258 duk_hstring *h_name; /* function name (borrowed reference), ends up in _name */
3259 /* h_code: held in bw_code */
3260 duk_hobject *h_consts; /* array */
3261 duk_hobject *h_funcs; /* array of function templates: [func1, offset1, line1, func2, offset2, line2]
3262 * offset/line points to closing brace to allow skipping on pass 2
3263 */
3264 duk_hobject *h_decls; /* array of declarations: [ name1, val1, name2, val2, ... ]
3265 * valN = (typeN) | (fnum << 8), where fnum is inner func number (0 for vars)
3266 * record function and variable declarations in pass 1
3267 */
3268 duk_hobject *h_labelnames; /* array of active label names */
3269 duk_hbuffer_dynamic *h_labelinfos; /* C array of duk_labelinfo */
3270 duk_hobject *h_argnames; /* array of formal argument names (-> _Formals) */
3271 duk_hobject *h_varmap; /* variable map for pass 2 (identifier -> register number or null (unmapped)) */
3272
3273 /* value stack indices for tracking objects */
3274 /* code_idx: not needed */
3275 duk_idx_t consts_idx;
3276 duk_idx_t funcs_idx;
3277 duk_idx_t decls_idx;
3278 duk_idx_t labelnames_idx;
3279 duk_idx_t labelinfos_idx;
3280 duk_idx_t argnames_idx;
3281 duk_idx_t varmap_idx;
3282
3283 /* temp reg handling */
3284 duk_reg_t temp_first; /* first register that is a temporary (below: variables) */
3285 duk_reg_t temp_next; /* next temporary register to allocate */
3286 duk_reg_t temp_max; /* highest value of temp_reg (temp_max - 1 is highest used reg) */
3287
3288 /* shuffle registers if large number of regs/consts */
3289 duk_reg_t shuffle1;
3290 duk_reg_t shuffle2;
3291 duk_reg_t shuffle3;
3292
3293 /* stats for current expression being parsed */
3294 duk_int_t nud_count;
3295 duk_int_t led_count;
3296 duk_int_t paren_level; /* parenthesis count, 0 = top level */
3297 duk_bool_t expr_lhs; /* expression is left-hand-side compatible */
3298 duk_bool_t allow_in; /* current paren level allows 'in' token */
3299
3300 /* misc */
3301 duk_int_t stmt_next; /* statement id allocation (running counter) */
3302 duk_int_t label_next; /* label id allocation (running counter) */
3303 duk_int_t catch_depth; /* catch stack depth */
3304 duk_int_t with_depth; /* with stack depth (affects identifier lookups) */
3305 duk_int_t fnum_next; /* inner function numbering */
3306 duk_int_t num_formals; /* number of formal arguments */
3307 duk_reg_t reg_stmt_value; /* register for writing value of 'non-empty' statements (global or eval code), -1 is marker */
3308#if defined(DUK_USE_DEBUGGER_SUPPORT)
3309 duk_int_t min_line; /* XXX: typing (duk_hcompiledfunction has duk_uint32_t) */
3310 duk_int_t max_line;
3311#endif
3312
3313 /* status booleans */
3314 duk_bool_t is_function; /* is an actual function (not global/eval code) */
3315 duk_bool_t is_eval; /* is eval code */
11fdf7f2
TL
3316 duk_bool_t is_global; /* is global code */
3317 duk_bool_t is_setget; /* is a setter/getter */
3318 duk_bool_t is_decl; /* is a function declaration (as opposed to function expression) */
3319 duk_bool_t is_strict; /* function is strict */
3320 duk_bool_t is_notail; /* function must not be tail called */
3321 duk_bool_t in_directive_prologue; /* parsing in "directive prologue", recognize directives */
3322 duk_bool_t in_scanning; /* parsing in "scanning" phase (first pass) */
3323 duk_bool_t may_direct_eval; /* function may call direct eval */
3324 duk_bool_t id_access_arguments; /* function refers to 'arguments' identifier */
3325 duk_bool_t id_access_slow; /* function makes one or more slow path accesses */
3326 duk_bool_t is_arguments_shadowed; /* argument/function declaration shadows 'arguments' */
3327 duk_bool_t needs_shuffle; /* function needs shuffle registers */
3328 duk_bool_t reject_regexp_in_adv; /* reject RegExp literal on next advance() call; needed for handling IdentifierName productions */
3329};
7c673cae 3330
11fdf7f2
TL
3331struct duk_compiler_ctx {
3332 duk_hthread *thr;
7c673cae 3333
11fdf7f2
TL
3334 /* filename being compiled (ends up in functions' '_filename' property) */
3335 duk_hstring *h_filename; /* borrowed reference */
7c673cae 3336
11fdf7f2
TL
3337 /* lexing (tokenization) state (contains two valstack slot indices) */
3338 duk_lexer_ctx lex;
7c673cae 3339
11fdf7f2
TL
3340 /* current and previous token for parsing */
3341 duk_token prev_token;
3342 duk_token curr_token;
3343 duk_idx_t tok11_idx; /* curr_token slot1 (matches 'lex' slot1_idx) */
3344 duk_idx_t tok12_idx; /* curr_token slot2 (matches 'lex' slot2_idx) */
3345 duk_idx_t tok21_idx; /* prev_token slot1 */
3346 duk_idx_t tok22_idx; /* prev_token slot2 */
7c673cae 3347
11fdf7f2
TL
3348 /* recursion limit */
3349 duk_int_t recursion_depth;
3350 duk_int_t recursion_limit;
7c673cae 3351
11fdf7f2
TL
3352 /* code emission temporary */
3353 duk_int_t emit_jumpslot_pc;
7c673cae 3354
11fdf7f2
TL
3355 /* current function being compiled (embedded instead of pointer for more compact access) */
3356 duk_compiler_func curr_func;
3357};
7c673cae 3358
11fdf7f2
TL
3359/*
3360 * Prototypes
3361 */
7c673cae 3362
11fdf7f2
TL
3363#define DUK_JS_COMPILE_FLAG_EVAL (1 << 0) /* source is eval code (not global) */
3364#define DUK_JS_COMPILE_FLAG_STRICT (1 << 1) /* strict outer context */
3365#define DUK_JS_COMPILE_FLAG_FUNCEXPR (1 << 2) /* source is a function expression (used for Function constructor) */
7c673cae 3366
11fdf7f2 3367DUK_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);
7c673cae 3368
11fdf7f2
TL
3369#endif /* DUK_JS_COMPILER_H_INCLUDED */
3370/*
3371 * Regular expression structs, constants, and bytecode defines.
3372 */
7c673cae 3373
11fdf7f2
TL
3374#ifndef DUK_REGEXP_H_INCLUDED
3375#define DUK_REGEXP_H_INCLUDED
7c673cae 3376
11fdf7f2
TL
3377/* maximum bytecode copies for {n,m} quantifiers */
3378#define DUK_RE_MAX_ATOM_COPIES 1000
7c673cae 3379
11fdf7f2
TL
3380/* regexp compilation limits */
3381#define DUK_RE_COMPILE_TOKEN_LIMIT 100000000L /* 1e8 */
7c673cae 3382
11fdf7f2
TL
3383/* regexp execution limits */
3384#define DUK_RE_EXECUTE_STEPS_LIMIT 1000000000L /* 1e9 */
7c673cae 3385
11fdf7f2
TL
3386/* regexp opcodes */
3387#define DUK_REOP_MATCH 1
3388#define DUK_REOP_CHAR 2
3389#define DUK_REOP_PERIOD 3
3390#define DUK_REOP_RANGES 4
3391#define DUK_REOP_INVRANGES 5
3392#define DUK_REOP_JUMP 6
3393#define DUK_REOP_SPLIT1 7
3394#define DUK_REOP_SPLIT2 8
3395#define DUK_REOP_SQMINIMAL 9
3396#define DUK_REOP_SQGREEDY 10
3397#define DUK_REOP_SAVE 11
3398#define DUK_REOP_WIPERANGE 12
3399#define DUK_REOP_LOOKPOS 13
3400#define DUK_REOP_LOOKNEG 14
3401#define DUK_REOP_BACKREFERENCE 15
3402#define DUK_REOP_ASSERT_START 16
3403#define DUK_REOP_ASSERT_END 17
3404#define DUK_REOP_ASSERT_WORD_BOUNDARY 18
3405#define DUK_REOP_ASSERT_NOT_WORD_BOUNDARY 19
7c673cae 3406
11fdf7f2
TL
3407/* flags */
3408#define DUK_RE_FLAG_GLOBAL (1 << 0)
3409#define DUK_RE_FLAG_IGNORE_CASE (1 << 1)
3410#define DUK_RE_FLAG_MULTILINE (1 << 2)
7c673cae 3411
11fdf7f2
TL
3412struct duk_re_matcher_ctx {
3413 duk_hthread *thr;
7c673cae 3414
11fdf7f2
TL
3415 duk_uint32_t re_flags;
3416 const duk_uint8_t *input;
3417 const duk_uint8_t *input_end;
3418 const duk_uint8_t *bytecode;
3419 const duk_uint8_t *bytecode_end;
3420 const duk_uint8_t **saved; /* allocated from valstack (fixed buffer) */
3421 duk_uint32_t nsaved;
3422 duk_uint32_t recursion_depth;
3423 duk_uint32_t recursion_limit;
3424 duk_uint32_t steps_count;
3425 duk_uint32_t steps_limit;
3426};
7c673cae 3427
11fdf7f2
TL
3428struct duk_re_compiler_ctx {
3429 duk_hthread *thr;
7c673cae 3430
11fdf7f2
TL
3431 duk_uint32_t re_flags;
3432 duk_lexer_ctx lex;
3433 duk_re_token curr_token;
3434 duk_bufwriter_ctx bw;
3435 duk_uint32_t captures; /* highest capture number emitted so far (used as: ++captures) */
3436 duk_uint32_t highest_backref;
3437 duk_uint32_t recursion_depth;
3438 duk_uint32_t recursion_limit;
3439 duk_uint32_t nranges; /* internal temporary value, used for char classes */
3440};
7c673cae 3441
11fdf7f2
TL
3442/*
3443 * Prototypes
3444 */
7c673cae 3445
11fdf7f2
TL
3446DUK_INTERNAL_DECL void duk_regexp_compile(duk_hthread *thr);
3447DUK_INTERNAL_DECL void duk_regexp_create_instance(duk_hthread *thr);
3448DUK_INTERNAL_DECL void duk_regexp_match(duk_hthread *thr);
3449DUK_INTERNAL_DECL void duk_regexp_match_force_global(duk_hthread *thr); /* hacky helper for String.prototype.split() */
7c673cae 3450
11fdf7f2 3451#endif /* DUK_REGEXP_H_INCLUDED */
7c673cae
FG
3452/*
3453 * Heap header definition and assorted macros, including ref counting.
3454 * Access all fields through the accessor macros.
3455 */
3456
3457#ifndef DUK_HEAPHDR_H_INCLUDED
3458#define DUK_HEAPHDR_H_INCLUDED
3459
3460/*
3461 * Common heap header
3462 *
3463 * All heap objects share the same flags and refcount fields. Objects other
3464 * than strings also need to have a single or double linked list pointers
3465 * for insertion into the "heap allocated" list. Strings are held in the
3466 * heap-wide string table so they don't need link pointers.
3467 *
3468 * Technically, 'h_refcount' must be wide enough to guarantee that it cannot
3469 * wrap (otherwise objects might be freed incorrectly after wrapping). This
3470 * means essentially that the refcount field must be as wide as data pointers.
3471 * On 64-bit platforms this means that the refcount needs to be 64 bits even
3472 * if an 'int' is 32 bits. This is a bit unfortunate, and compromising on
3473 * this might be reasonable in the future.
3474 *
3475 * Heap header size on 32-bit platforms: 8 bytes without reference counting,
3476 * 16 bytes with reference counting.
3477 */
3478
3479struct duk_heaphdr {
3480 duk_uint32_t h_flags;
3481
3482#if defined(DUK_USE_REFERENCE_COUNTING)
3483#if defined(DUK_USE_REFCOUNT16)
3484 duk_uint16_t h_refcount16;
3485#else
3486 duk_size_t h_refcount;
3487#endif
3488#endif
3489
3490#if defined(DUK_USE_HEAPPTR16)
3491 duk_uint16_t h_next16;
3492#else
3493 duk_heaphdr *h_next;
3494#endif
3495
3496#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
3497 /* refcounting requires direct heap frees, which in turn requires a dual linked heap */
3498#if defined(DUK_USE_HEAPPTR16)
3499 duk_uint16_t h_prev16;
3500#else
3501 duk_heaphdr *h_prev;
3502#endif
3503#endif
3504
3505 /* When DUK_USE_HEAPPTR16 (and DUK_USE_REFCOUNT16) is in use, the
3506 * struct won't align nicely to 4 bytes. This 16-bit extra field
3507 * is added to make the alignment clean; the field can be used by
3508 * heap objects when 16-bit packing is used. This field is now
3509 * conditional to DUK_USE_HEAPPTR16 only, but it is intended to be
3510 * used with DUK_USE_REFCOUNT16 and DUK_USE_DOUBLE_LINKED_HEAP;
3511 * this only matter to low memory environments anyway.
3512 */
3513#if defined(DUK_USE_HEAPPTR16)
3514 duk_uint16_t h_extra16;
3515#endif
3516};
3517
3518struct duk_heaphdr_string {
3519 /* 16 bits would be enough for shared heaphdr flags and duk_hstring
3520 * flags. The initial parts of duk_heaphdr_string and duk_heaphdr
3521 * must match so changing the flags field size here would be quite
3522 * awkward. However, to minimize struct size, we can pack at least
3523 * 16 bits of duk_hstring data into the flags field.
3524 */
3525 duk_uint32_t h_flags;
3526
3527#if defined(DUK_USE_REFERENCE_COUNTING)
3528#if defined(DUK_USE_REFCOUNT16)
3529 duk_uint16_t h_refcount16;
11fdf7f2 3530 duk_uint16_t h_strextra16; /* round out to 8 bytes */
7c673cae
FG
3531#else
3532 duk_size_t h_refcount;
3533#endif
11fdf7f2
TL
3534#else
3535 duk_uint16_t h_strextra16;
7c673cae
FG
3536#endif
3537};
3538
3539#define DUK_HEAPHDR_FLAGS_TYPE_MASK 0x00000003UL
3540#define DUK_HEAPHDR_FLAGS_FLAG_MASK (~DUK_HEAPHDR_FLAGS_TYPE_MASK)
3541
3542 /* 2 bits for heap type */
11fdf7f2
TL
3543#define DUK_HEAPHDR_FLAGS_HEAP_START 2 /* 5 heap flags */
3544#define DUK_HEAPHDR_FLAGS_USER_START 7 /* 25 user flags */
7c673cae
FG
3545
3546#define DUK_HEAPHDR_HEAP_FLAG_NUMBER(n) (DUK_HEAPHDR_FLAGS_HEAP_START + (n))
3547#define DUK_HEAPHDR_USER_FLAG_NUMBER(n) (DUK_HEAPHDR_FLAGS_USER_START + (n))
3548#define DUK_HEAPHDR_HEAP_FLAG(n) (1UL << (DUK_HEAPHDR_FLAGS_HEAP_START + (n)))
3549#define DUK_HEAPHDR_USER_FLAG(n) (1UL << (DUK_HEAPHDR_FLAGS_USER_START + (n)))
3550
3551#define DUK_HEAPHDR_FLAG_REACHABLE DUK_HEAPHDR_HEAP_FLAG(0) /* mark-and-sweep: reachable */
3552#define DUK_HEAPHDR_FLAG_TEMPROOT DUK_HEAPHDR_HEAP_FLAG(1) /* mark-and-sweep: children not processed */
3553#define DUK_HEAPHDR_FLAG_FINALIZABLE DUK_HEAPHDR_HEAP_FLAG(2) /* mark-and-sweep: finalizable (on current pass) */
3554#define DUK_HEAPHDR_FLAG_FINALIZED DUK_HEAPHDR_HEAP_FLAG(3) /* mark-and-sweep: finalized (on previous pass) */
11fdf7f2 3555#define DUK_HEAPHDR_FLAG_READONLY DUK_HEAPHDR_HEAP_FLAG(4) /* read-only object, in code section */
7c673cae
FG
3556
3557#define DUK_HTYPE_MIN 1
3558#define DUK_HTYPE_STRING 1
3559#define DUK_HTYPE_OBJECT 2
3560#define DUK_HTYPE_BUFFER 3
3561#define DUK_HTYPE_MAX 3
3562
3563#if defined(DUK_USE_HEAPPTR16)
3564#define DUK_HEAPHDR_GET_NEXT(heap,h) \
3565 ((duk_heaphdr *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->h_next16))
3566#define DUK_HEAPHDR_SET_NEXT(heap,h,val) do { \
3567 (h)->h_next16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) val); \
3568 } while (0)
3569#else
3570#define DUK_HEAPHDR_GET_NEXT(heap,h) ((h)->h_next)
3571#define DUK_HEAPHDR_SET_NEXT(heap,h,val) do { \
3572 (h)->h_next = (val); \
3573 } while (0)
3574#endif
3575
3576#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
3577#if defined(DUK_USE_HEAPPTR16)
3578#define DUK_HEAPHDR_GET_PREV(heap,h) \
3579 ((duk_heaphdr *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->h_prev16))
3580#define DUK_HEAPHDR_SET_PREV(heap,h,val) do { \
3581 (h)->h_prev16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (val)); \
3582 } while (0)
3583#else
3584#define DUK_HEAPHDR_GET_PREV(heap,h) ((h)->h_prev)
3585#define DUK_HEAPHDR_SET_PREV(heap,h,val) do { \
3586 (h)->h_prev = (val); \
3587 } while (0)
3588#endif
3589#endif
3590
3591#if defined(DUK_USE_REFERENCE_COUNTING)
3592#if defined(DUK_USE_REFCOUNT16)
3593#define DUK_HEAPHDR_GET_REFCOUNT(h) ((h)->h_refcount16)
3594#define DUK_HEAPHDR_SET_REFCOUNT(h,val) do { \
3595 (h)->h_refcount16 = (val); \
3596 } while (0)
3597#define DUK_HEAPHDR_PREINC_REFCOUNT(h) (++(h)->h_refcount16) /* result: updated refcount */
3598#define DUK_HEAPHDR_PREDEC_REFCOUNT(h) (--(h)->h_refcount16) /* result: updated refcount */
3599#else
3600#define DUK_HEAPHDR_GET_REFCOUNT(h) ((h)->h_refcount)
3601#define DUK_HEAPHDR_SET_REFCOUNT(h,val) do { \
3602 (h)->h_refcount = (val); \
3603 } while (0)
3604#define DUK_HEAPHDR_PREINC_REFCOUNT(h) (++(h)->h_refcount) /* result: updated refcount */
3605#define DUK_HEAPHDR_PREDEC_REFCOUNT(h) (--(h)->h_refcount) /* result: updated refcount */
3606#endif
3607#else
3608/* refcount macros not defined without refcounting, caller must #ifdef now */
3609#endif /* DUK_USE_REFERENCE_COUNTING */
3610
3611/*
3612 * Note: type is treated as a field separate from flags, so some masking is
3613 * involved in the macros below.
3614 */
3615
3616#define DUK_HEAPHDR_GET_FLAGS_RAW(h) ((h)->h_flags)
3617
3618#define DUK_HEAPHDR_GET_FLAGS(h) ((h)->h_flags & DUK_HEAPHDR_FLAGS_FLAG_MASK)
3619#define DUK_HEAPHDR_SET_FLAGS(h,val) do { \
3620 (h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) | (val); \
3621 } while (0)
3622
3623#define DUK_HEAPHDR_GET_TYPE(h) ((h)->h_flags & DUK_HEAPHDR_FLAGS_TYPE_MASK)
3624#define DUK_HEAPHDR_SET_TYPE(h,val) do { \
3625 (h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_TYPE_MASK)) | (val); \
3626 } while (0)
3627
3628#define DUK_HEAPHDR_HTYPE_VALID(h) ( \
3629 DUK_HEAPHDR_GET_TYPE((h)) >= DUK_HTYPE_MIN && \
3630 DUK_HEAPHDR_GET_TYPE((h)) <= DUK_HTYPE_MAX \
3631 )
3632
3633#define DUK_HEAPHDR_SET_TYPE_AND_FLAGS(h,tval,fval) do { \
3634 (h)->h_flags = ((tval) & DUK_HEAPHDR_FLAGS_TYPE_MASK) | \
3635 ((fval) & DUK_HEAPHDR_FLAGS_FLAG_MASK); \
3636 } while (0)
3637
3638#define DUK_HEAPHDR_SET_FLAG_BITS(h,bits) do { \
3639 DUK_ASSERT(((bits) & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) == 0); \
3640 (h)->h_flags |= (bits); \
3641 } while (0)
3642
3643#define DUK_HEAPHDR_CLEAR_FLAG_BITS(h,bits) do { \
3644 DUK_ASSERT(((bits) & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) == 0); \
3645 (h)->h_flags &= ~((bits)); \
3646 } while (0)
3647
3648#define DUK_HEAPHDR_CHECK_FLAG_BITS(h,bits) (((h)->h_flags & (bits)) != 0)
3649
3650#define DUK_HEAPHDR_SET_REACHABLE(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE)
3651#define DUK_HEAPHDR_CLEAR_REACHABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE)
3652#define DUK_HEAPHDR_HAS_REACHABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE)
3653
3654#define DUK_HEAPHDR_SET_TEMPROOT(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT)
3655#define DUK_HEAPHDR_CLEAR_TEMPROOT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT)
3656#define DUK_HEAPHDR_HAS_TEMPROOT(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT)
3657
3658#define DUK_HEAPHDR_SET_FINALIZABLE(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE)
3659#define DUK_HEAPHDR_CLEAR_FINALIZABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE)
3660#define DUK_HEAPHDR_HAS_FINALIZABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE)
3661
3662#define DUK_HEAPHDR_SET_FINALIZED(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED)
3663#define DUK_HEAPHDR_CLEAR_FINALIZED(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED)
3664#define DUK_HEAPHDR_HAS_FINALIZED(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED)
3665
11fdf7f2
TL
3666#define DUK_HEAPHDR_SET_READONLY(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY)
3667#define DUK_HEAPHDR_CLEAR_READONLY(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY)
3668#define DUK_HEAPHDR_HAS_READONLY(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY)
3669
7c673cae
FG
3670/* get or set a range of flags; m=first bit number, n=number of bits */
3671#define DUK_HEAPHDR_GET_FLAG_RANGE(h,m,n) (((h)->h_flags >> (m)) & ((1UL << (n)) - 1UL))
3672
3673#define DUK_HEAPHDR_SET_FLAG_RANGE(h,m,n,v) do { \
3674 (h)->h_flags = \
11fdf7f2 3675 ((h)->h_flags & (~(((1UL << (n)) - 1UL) << (m)))) \
7c673cae
FG
3676 | ((v) << (m)); \
3677 } while (0)
3678
3679/* init pointer fields to null */
3680#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
3681#define DUK_HEAPHDR_INIT_NULLS(h) do { \
3682 DUK_HEAPHDR_SET_NEXT((h), (void *) NULL); \
3683 DUK_HEAPHDR_SET_PREV((h), (void *) NULL); \
3684 } while (0)
3685#else
3686#define DUK_HEAPHDR_INIT_NULLS(h) do { \
3687 DUK_HEAPHDR_SET_NEXT((h), (void *) NULL); \
3688 } while (0)
3689#endif
3690
3691#define DUK_HEAPHDR_STRING_INIT_NULLS(h) /* currently nop */
3692
11fdf7f2
TL
3693/*
3694 * Assert helpers
3695 */
3696
3697/* Check that prev/next links are consistent: if e.g. h->prev is != NULL,
3698 * h->prev->next should point back to h.
3699 */
3700#if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_ASSERTIONS)
3701#define DUK_ASSERT_HEAPHDR_LINKS(heap,h) do { \
3702 if ((h) != NULL) { \
3703 duk_heaphdr *h__prev, *h__next; \
3704 h__prev = DUK_HEAPHDR_GET_PREV((heap), (h)); \
3705 h__next = DUK_HEAPHDR_GET_NEXT((heap), (h)); \
3706 DUK_ASSERT(h__prev == NULL || (DUK_HEAPHDR_GET_NEXT((heap), h__prev) == (h))); \
3707 DUK_ASSERT(h__next == NULL || (DUK_HEAPHDR_GET_PREV((heap), h__next) == (h))); \
3708 } \
3709 } while (0)
3710#else
3711#define DUK_ASSERT_HEAPHDR_LINKS(heap,h) do {} while (0)
3712#endif
3713
7c673cae
FG
3714/*
3715 * Reference counting helper macros. The macros take a thread argument
3716 * and must thus always be executed in a specific thread context. The
3717 * thread argument is needed for features like finalization. Currently
3718 * it is not required for INCREF, but it is included just in case.
3719 *
3720 * Note that 'raw' macros such as DUK_HEAPHDR_GET_REFCOUNT() are not
3721 * defined without DUK_USE_REFERENCE_COUNTING, so caller must #ifdef
3722 * around them.
3723 */
3724
3725#if defined(DUK_USE_REFERENCE_COUNTING)
3726
11fdf7f2
TL
3727#if defined(DUK_USE_ROM_OBJECTS)
3728/* With ROM objects "needs refcount update" is true when the value is
3729 * heap allocated and is not a ROM object.
3730 */
3731/* XXX: double evaluation for 'tv' argument. */
3732#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) \
3733 (DUK_TVAL_IS_HEAP_ALLOCATED((tv)) && !DUK_HEAPHDR_HAS_READONLY(DUK_TVAL_GET_HEAPHDR((tv))))
3734#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) (!DUK_HEAPHDR_HAS_READONLY((h)))
3735#else /* DUK_USE_ROM_OBJECTS */
3736/* Without ROM objects "needs refcount update" == is heap allocated. */
3737#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) DUK_TVAL_IS_HEAP_ALLOCATED((tv))
3738#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) 1
3739#endif /* DUK_USE_ROM_OBJECTS */
3740
7c673cae
FG
3741/* Fast variants, inline refcount operations except for refzero handling.
3742 * Can be used explicitly when speed is always more important than size.
3743 * For a good compiler and a single file build, these are basically the
3744 * same as a forced inline.
3745 */
3746#define DUK_TVAL_INCREF_FAST(thr,tv) do { \
3747 duk_tval *duk__tv = (tv); \
3748 DUK_ASSERT(duk__tv != NULL); \
11fdf7f2 3749 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \
7c673cae
FG
3750 duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \
3751 DUK_ASSERT(duk__h != NULL); \
3752 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
3753 DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \
3754 } \
3755 } while (0)
3756#define DUK_TVAL_DECREF_FAST(thr,tv) do { \
3757 duk_tval *duk__tv = (tv); \
3758 DUK_ASSERT(duk__tv != NULL); \
11fdf7f2 3759 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \
7c673cae
FG
3760 duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \
3761 DUK_ASSERT(duk__h != NULL); \
3762 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
3763 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \
3764 if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \
3765 duk_heaphdr_refzero((thr), duk__h); \
3766 } \
3767 } \
3768 } while (0)
3769#define DUK_HEAPHDR_INCREF_FAST(thr,h) do { \
3770 duk_heaphdr *duk__h = (duk_heaphdr *) (h); \
3771 DUK_ASSERT(duk__h != NULL); \
3772 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
11fdf7f2
TL
3773 if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \
3774 DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \
3775 } \
7c673cae
FG
3776 } while (0)
3777#define DUK_HEAPHDR_DECREF_FAST(thr,h) do { \
3778 duk_heaphdr *duk__h = (duk_heaphdr *) (h); \
3779 DUK_ASSERT(duk__h != NULL); \
3780 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
3781 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \
11fdf7f2
TL
3782 if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \
3783 if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \
3784 duk_heaphdr_refzero((thr), duk__h); \
3785 } \
7c673cae
FG
3786 } \
3787 } while (0)
3788
3789/* Slow variants, call to a helper to reduce code size.
3790 * Can be used explicitly when size is always more important than speed.
3791 */
3792#define DUK_TVAL_INCREF_SLOW(thr,tv) do { \
3793 duk_tval_incref((tv)); \
3794 } while (0)
3795#define DUK_TVAL_DECREF_SLOW(thr,tv) do { \
3796 duk_tval_decref((thr), (tv)); \
3797 } while (0)
3798#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do { \
3799 duk_heaphdr_incref((duk_heaphdr *) (h)); \
3800 } while (0)
3801#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do { \
3802 duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); \
3803 } while (0)
3804
3805/* Default variants. Selection depends on speed/size preference.
3806 * Concretely: with gcc 4.8.1 -Os x64 the difference in final binary
3807 * is about +1kB for _FAST variants.
3808 */
3809#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
3810#define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_FAST((thr),(tv))
3811#define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_FAST((thr),(tv))
3812#define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_FAST((thr),(h))
3813#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST((thr),(h))
3814#else
3815#define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_SLOW((thr),(tv))
3816#define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_SLOW((thr),(tv))
3817#define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_SLOW((thr),(h))
3818#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_SLOW((thr),(h))
3819#endif
3820
3821/* Casting convenience. */
3822#define DUK_HSTRING_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
3823#define DUK_HSTRING_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
3824#define DUK_HOBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
3825#define DUK_HOBJECT_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
3826#define DUK_HBUFFER_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
3827#define DUK_HBUFFER_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
3828#define DUK_HCOMPILEDFUNCTION_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
3829#define DUK_HCOMPILEDFUNCTION_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
3830#define DUK_HNATIVEFUNCTION_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
3831#define DUK_HNATIVEFUNCTION_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
3832#define DUK_HBUFFEROBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
3833#define DUK_HBUFFEROBJECT_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
3834#define DUK_HTHREAD_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
3835#define DUK_HTHREAD_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
3836
3837/* Convenience for some situations; the above macros don't allow NULLs
3838 * for performance reasons.
3839 */
3840#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do { \
3841 if ((h) != NULL) { \
3842 DUK_HEAPHDR_INCREF((thr), (duk_heaphdr *) (h)); \
3843 } \
3844 } while (0)
3845#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do { \
3846 if ((h) != NULL) { \
3847 DUK_HEAPHDR_DECREF((thr), (duk_heaphdr *) (h)); \
3848 } \
3849 } while (0)
3850
11fdf7f2
TL
3851/*
3852 * Macros to set a duk_tval and update refcount of the target (decref the
3853 * old value and incref the new value if necessary). This is both performance
3854 * and footprint critical; any changes made should be measured for size/speed.
3855 */
3856
3857#define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \
3858 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3859 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3860 DUK_TVAL_SET_UNDEFINED(tv__dst); \
3861 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3862 } while (0)
3863
3864#define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \
3865 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3866 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3867 DUK_TVAL_SET_UNUSED(tv__dst); \
3868 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3869 } while (0)
3870
3871#define DUK_TVAL_SET_NULL_UPDREF_ALT0(thr,tvptr_dst) do { \
3872 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3873 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3874 DUK_TVAL_SET_NULL(tv__dst); \
3875 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3876 } while (0)
3877
3878#define DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
3879 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3880 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3881 DUK_TVAL_SET_BOOLEAN(tv__dst, (newval)); \
3882 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3883 } while (0)
3884
3885#define DUK_TVAL_SET_NUMBER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
3886 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3887 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3888 DUK_TVAL_SET_NUMBER(tv__dst, (newval)); \
3889 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3890 } while (0)
3891#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
3892 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3893 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3894 DUK_TVAL_SET_NUMBER_CHKFAST(tv__dst, (newval)); \
3895 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3896 } while (0)
3897#define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
3898 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3899 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3900 DUK_TVAL_SET_DOUBLE(tv__dst, (newval)); \
3901 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3902 } while (0)
3903#define DUK_TVAL_SET_NAN_UPDREF_ALT0(thr,tvptr_dst) do { \
3904 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3905 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3906 DUK_TVAL_SET_NAN(tv__dst); \
3907 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3908 } while (0)
3909#if defined(DUK_USE_FASTINT)
3910#define DUK_TVAL_SET_FASTINT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
3911 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3912 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3913 DUK_TVAL_SET_FASTINT(tv__dst, (newval)); \
3914 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3915 } while (0)
3916#define DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
3917 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3918 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3919 DUK_TVAL_SET_FASTINT_I32(tv__dst, (newval)); \
3920 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3921 } while (0)
3922#define DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
3923 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3924 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3925 DUK_TVAL_SET_FASTINT_U32(tv__dst, (newval)); \
3926 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3927 } while (0)
3928#else
3929#define DUK_TVAL_SET_DOUBLE_CAST_UPDREF(thr,tvptr_dst,newval) \
3930 DUK_TVAL_SET_DOUBLE_UPDREF((thr), (tvptr_dst), (duk_double_t) (newval))
3931#endif /* DUK_USE_FASTINT */
3932
3933#define DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0(thr,tvptr_dst,lf_v,lf_fp,lf_flags) do { \
3934 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3935 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3936 DUK_TVAL_SET_LIGHTFUNC(tv__dst, (lf_v), (lf_fp), (lf_flags)); \
3937 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3938 } while (0)
3939
3940#define DUK_TVAL_SET_STRING_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
3941 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3942 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3943 DUK_TVAL_SET_STRING(tv__dst, (newval)); \
3944 DUK_HSTRING_INCREF((thr), (newval)); \
3945 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3946 } while (0)
3947
3948#define DUK_TVAL_SET_OBJECT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
3949 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3950 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3951 DUK_TVAL_SET_OBJECT(tv__dst, (newval)); \
3952 DUK_HOBJECT_INCREF((thr), (newval)); \
3953 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3954 } while (0)
3955
3956#define DUK_TVAL_SET_BUFFER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
3957 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3958 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3959 DUK_TVAL_SET_BUFFER(tv__dst, (newval)); \
3960 DUK_HBUFFER_INCREF((thr), (newval)); \
3961 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3962 } while (0)
3963
3964#define DUK_TVAL_SET_POINTER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
3965 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
3966 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3967 DUK_TVAL_SET_POINTER(tv__dst, (newval)); \
3968 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3969 } while (0)
3970
3971/* DUK_TVAL_SET_TVAL_UPDREF() is used a lot in executor, property lookups,
3972 * etc, so it's very important for performance. Measure when changing.
3973 *
3974 * NOTE: the source and destination duk_tval pointers may be the same, and
3975 * the macros MUST deal with that correctly.
3976 */
3977
3978/* Original idiom used, minimal code size. */
3979#define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \
3980 duk_tval *tv__dst, *tv__src; duk_tval tv__tmp; \
3981 tv__dst = (tvptr_dst); tv__src = (tvptr_src); \
3982 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
3983 DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
3984 DUK_TVAL_INCREF((thr), tv__src); \
3985 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
3986 } while (0)
3987
3988/* Faster alternative: avoid making a temporary copy of tvptr_dst and use
3989 * fast incref/decref macros.
3990 */
3991#define DUK_TVAL_SET_TVAL_UPDREF_ALT1(thr,tvptr_dst,tvptr_src) do { \
3992 duk_tval *tv__dst, *tv__src; duk_heaphdr *h__obj; \
3993 tv__dst = (tvptr_dst); tv__src = (tvptr_src); \
3994 DUK_TVAL_INCREF_FAST((thr), tv__src); \
3995 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv__dst)) { \
3996 h__obj = DUK_TVAL_GET_HEAPHDR(tv__dst); \
3997 DUK_ASSERT(h__obj != NULL); \
3998 DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
3999 DUK_HEAPHDR_DECREF_FAST((thr), h__obj); /* side effects */ \
4000 } else { \
4001 DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
4002 } \
4003 } while (0)
4004
4005/* XXX: no optimized variants yet */
4006#define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0
4007#define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0
4008#define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0
4009#define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0
4010#define DUK_TVAL_SET_NUMBER_UPDREF DUK_TVAL_SET_NUMBER_UPDREF_ALT0
4011#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0
4012#define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0
4013#define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0
4014#if defined(DUK_USE_FASTINT)
4015#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_FASTINT_UPDREF_ALT0
4016#define DUK_TVAL_SET_FASTINT_I32_UPDREF DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0
4017#define DUK_TVAL_SET_FASTINT_U32_UPDREF DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0
4018#else
4019#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast int-to-double */
4020#define DUK_TVAL_SET_FASTINT_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
4021#define DUK_TVAL_SET_FASTINT_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
4022#endif /* DUK_USE_FASTINT */
4023#define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0
4024#define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0
4025#define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0
4026#define DUK_TVAL_SET_BUFFER_UPDREF DUK_TVAL_SET_BUFFER_UPDREF_ALT0
4027#define DUK_TVAL_SET_POINTER_UPDREF DUK_TVAL_SET_POINTER_UPDREF_ALT0
4028
4029#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
4030/* Optimized for speed. */
4031#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT1
4032#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT1
4033#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0
4034#else
4035/* Optimized for size. */
4036#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT0
4037#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT0
4038#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0
4039#endif
4040
7c673cae
FG
4041#else /* DUK_USE_REFERENCE_COUNTING */
4042
11fdf7f2
TL
4043#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) 0
4044#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) 0
4045
7c673cae
FG
4046#define DUK_TVAL_INCREF_FAST(thr,v) do {} while (0) /* nop */
4047#define DUK_TVAL_DECREF_FAST(thr,v) do {} while (0) /* nop */
4048#define DUK_TVAL_INCREF_SLOW(thr,v) do {} while (0) /* nop */
4049#define DUK_TVAL_DECREF_SLOW(thr,v) do {} while (0) /* nop */
4050#define DUK_TVAL_INCREF(thr,v) do {} while (0) /* nop */
4051#define DUK_TVAL_DECREF(thr,v) do {} while (0) /* nop */
4052#define DUK_HEAPHDR_INCREF_FAST(thr,h) do {} while (0) /* nop */
4053#define DUK_HEAPHDR_DECREF_FAST(thr,h) do {} while (0) /* nop */
4054#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do {} while (0) /* nop */
4055#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do {} while (0) /* nop */
4056#define DUK_HEAPHDR_INCREF(thr,h) do {} while (0) /* nop */
4057#define DUK_HEAPHDR_DECREF(thr,h) do {} while (0) /* nop */
4058#define DUK_HSTRING_INCREF(thr,h) do {} while (0) /* nop */
4059#define DUK_HSTRING_DECREF(thr,h) do {} while (0) /* nop */
4060#define DUK_HOBJECT_INCREF(thr,h) do {} while (0) /* nop */
4061#define DUK_HOBJECT_DECREF(thr,h) do {} while (0) /* nop */
4062#define DUK_HBUFFER_INCREF(thr,h) do {} while (0) /* nop */
4063#define DUK_HBUFFER_DECREF(thr,h) do {} while (0) /* nop */
4064#define DUK_HCOMPILEDFUNCTION_INCREF(thr,h) do {} while (0) /* nop */
4065#define DUK_HCOMPILEDFUNCTION_DECREF(thr,h) do {} while (0) /* nop */
4066#define DUK_HNATIVEFUNCTION_INCREF(thr,h) do {} while (0) /* nop */
4067#define DUK_HNATIVEFUNCTION_DECREF(thr,h) do {} while (0) /* nop */
4068#define DUK_HBUFFEROBJECT_INCREF(thr,h) do {} while (0) /* nop */
4069#define DUK_HBUFFEROBJECT_DECREF(thr,h) do {} while (0) /* nop */
4070#define DUK_HTHREAD_INCREF(thr,h) do {} while (0) /* nop */
4071#define DUK_HTHREAD_DECREF(thr,h) do {} while (0) /* nop */
4072#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do {} while (0) /* nop */
4073#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do {} while (0) /* nop */
4074
11fdf7f2
TL
4075#define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \
4076 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4077 DUK_TVAL_SET_UNDEFINED(tv__dst); \
4078 DUK_UNREF((thr)); \
4079 } while (0)
4080
4081#define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \
4082 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4083 DUK_TVAL_SET_UNUSED(tv__dst); \
4084 DUK_UNREF((thr)); \
4085 } while (0)
4086
4087#define DUK_TVAL_SET_NULL_UPDREF_ALT0(thr,tvptr_dst) do { \
4088 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4089 DUK_TVAL_SET_NULL(tv__dst); \
4090 DUK_UNREF((thr)); \
4091 } while (0)
4092
4093#define DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4094 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4095 DUK_TVAL_SET_BOOLEAN(tv__dst, (newval)); \
4096 DUK_UNREF((thr)); \
4097 } while (0)
4098
4099#define DUK_TVAL_SET_NUMBER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4100 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4101 DUK_TVAL_SET_NUMBER(tv__dst, (newval)); \
4102 DUK_UNREF((thr)); \
4103 } while (0)
4104#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4105 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4106 DUK_TVAL_SET_NUMBER_CHKFAST(tv__dst, (newval)); \
4107 DUK_UNREF((thr)); \
4108 } while (0)
4109#define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4110 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4111 DUK_TVAL_SET_DOUBLE(tv__dst, (newval)); \
4112 DUK_UNREF((thr)); \
4113 } while (0)
4114#define DUK_TVAL_SET_NAN_UPDREF_ALT0(thr,tvptr_dst) do { \
4115 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4116 DUK_TVAL_SET_NAN(tv__dst); \
4117 DUK_UNREF((thr)); \
4118 } while (0)
4119#if defined(DUK_USE_FASTINT)
4120#define DUK_TVAL_SET_FASTINT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4121 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4122 DUK_TVAL_SET_FASTINT(tv__dst, (newval)); \
4123 DUK_UNREF((thr)); \
4124 } while (0)
4125#define DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4126 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4127 DUK_TVAL_SET_FASTINT_I32(tv__dst, (newval)); \
4128 DUK_UNREF((thr)); \
4129 } while (0)
4130#define DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4131 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4132 DUK_TVAL_SET_FASTINT_U32(tv__dst, (newval)); \
4133 DUK_UNREF((thr)); \
4134 } while (0)
4135#else
4136#define DUK_TVAL_SET_DOUBLE_CAST_UPDREF(thr,tvptr_dst,newval) \
4137 DUK_TVAL_SET_DOUBLE_UPDREF((thr), (tvptr_dst), (duk_double_t) (newval))
4138#endif /* DUK_USE_FASTINT */
4139
4140#define DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0(thr,tvptr_dst,lf_v,lf_fp,lf_flags) do { \
4141 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4142 DUK_TVAL_SET_LIGHTFUNC(tv__dst, (lf_v), (lf_fp), (lf_flags)); \
4143 DUK_UNREF((thr)); \
4144 } while (0)
4145
4146#define DUK_TVAL_SET_STRING_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4147 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4148 DUK_TVAL_SET_STRING(tv__dst, (newval)); \
4149 DUK_UNREF((thr)); \
4150 } while (0)
4151
4152#define DUK_TVAL_SET_OBJECT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4153 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4154 DUK_TVAL_SET_OBJECT(tv__dst, (newval)); \
4155 DUK_UNREF((thr)); \
4156 } while (0)
4157
4158#define DUK_TVAL_SET_BUFFER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4159 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4160 DUK_TVAL_SET_BUFFER(tv__dst, (newval)); \
4161 DUK_UNREF((thr)); \
4162 } while (0)
4163
4164#define DUK_TVAL_SET_POINTER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4165 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4166 DUK_TVAL_SET_POINTER(tv__dst, (newval)); \
4167 DUK_UNREF((thr)); \
4168 } while (0)
4169
4170#define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \
4171 duk_tval *tv__dst, *tv__src; \
4172 tv__dst = (tvptr_dst); tv__src = (tvptr_src); \
4173 DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
4174 DUK_UNREF((thr)); \
4175 } while (0)
4176
4177#define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0
4178#define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0
4179#define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0
4180#define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0
4181#define DUK_TVAL_SET_NUMBER_UPDREF DUK_TVAL_SET_NUMBER_UPDREF_ALT0
4182#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0
4183#define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0
4184#define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0
4185#if defined(DUK_USE_FASTINT)
4186#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_FASTINT_UPDREF_ALT0
4187#define DUK_TVAL_SET_FASTINT_I32_UPDREF DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0
4188#define DUK_TVAL_SET_FASTINT_U32_UPDREF DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0
4189#else
4190#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast-int-to-double */
4191#define DUK_TVAL_SET_FASTINT_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
4192#define DUK_TVAL_SET_FASTINT_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
4193#endif /* DUK_USE_FASTINT */
4194#define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0
4195#define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0
4196#define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0
4197#define DUK_TVAL_SET_BUFFER_UPDREF DUK_TVAL_SET_BUFFER_UPDREF_ALT0
4198#define DUK_TVAL_SET_POINTER_UPDREF DUK_TVAL_SET_POINTER_UPDREF_ALT0
4199
4200#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT0
4201#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT0
4202#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0
4203
7c673cae
FG
4204#endif /* DUK_USE_REFERENCE_COUNTING */
4205
4206#endif /* DUK_HEAPHDR_H_INCLUDED */
7c673cae
FG
4207/*
4208 * Internal API calls which have (stack and other) semantics similar
4209 * to the public API.
4210 */
4211
4212#ifndef DUK_API_INTERNAL_H_INCLUDED
4213#define DUK_API_INTERNAL_H_INCLUDED
4214
4215/* duk_push_sprintf constants */
4216#define DUK_PUSH_SPRINTF_INITIAL_SIZE 256L
4217#define DUK_PUSH_SPRINTF_SANITY_LIMIT (1L * 1024L * 1024L * 1024L)
4218
4219/* Flag ORed to err_code to indicate __FILE__ / __LINE__ is not
4220 * blamed as source of error for error fileName / lineNumber.
4221 */
4222#define DUK_ERRCODE_FLAG_NOBLAME_FILELINE (1L << 24)
4223
4224/* Valstack resize flags */
4225#define DUK_VSRESIZE_FLAG_SHRINK (1 << 0)
4226#define DUK_VSRESIZE_FLAG_COMPACT (1 << 1)
4227#define DUK_VSRESIZE_FLAG_THROW (1 << 2)
4228
4229/* Current convention is to use duk_size_t for value stack sizes and global indices,
4230 * and duk_idx_t for local frame indices.
4231 */
4232DUK_INTERNAL_DECL
4233duk_bool_t duk_valstack_resize_raw(duk_context *ctx,
4234 duk_size_t min_new_size,
4235 duk_small_uint_t flags);
4236
11fdf7f2
TL
4237#if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS)
4238DUK_INTERNAL_DECL const char *duk_get_type_name(duk_context *ctx, duk_idx_t index);
4239#endif
4240
7c673cae
FG
4241DUK_INTERNAL_DECL duk_tval *duk_get_tval(duk_context *ctx, duk_idx_t index);
4242DUK_INTERNAL_DECL duk_tval *duk_require_tval(duk_context *ctx, duk_idx_t index);
4243DUK_INTERNAL_DECL void duk_push_tval(duk_context *ctx, duk_tval *tv);
4244
4245/* Push the current 'this' binding; throw TypeError if binding is not object
4246 * coercible (CheckObjectCoercible).
4247 */
4248DUK_INTERNAL_DECL void duk_push_this_check_object_coercible(duk_context *ctx);
4249
4250/* duk_push_this() + CheckObjectCoercible() + duk_to_object() */
4251DUK_INTERNAL_DECL duk_hobject *duk_push_this_coercible_to_object(duk_context *ctx);
4252
4253/* duk_push_this() + CheckObjectCoercible() + duk_to_string() */
4254DUK_INTERNAL_DECL duk_hstring *duk_push_this_coercible_to_string(duk_context *ctx);
4255
4256/* Get a borrowed duk_tval pointer to the current 'this' binding. Caller must
4257 * make sure there's an active callstack entry. Note that the returned pointer
4258 * is unstable with regards to side effects.
4259 */
4260DUK_INTERNAL_DECL duk_tval *duk_get_borrowed_this_tval(duk_context *ctx);
4261
4262/* XXX: add fastint support? */
4263#define duk_push_u64(ctx,val) \
4264 duk_push_number((ctx), (duk_double_t) (val))
4265#define duk_push_i64(ctx,val) \
4266 duk_push_number((ctx), (duk_double_t) (val))
4267
4268/* duk_push_(u)int() is guaranteed to support at least (un)signed 32-bit range */
4269#define duk_push_u32(ctx,val) \
4270 duk_push_uint((ctx), (duk_uint_t) (val))
4271#define duk_push_i32(ctx,val) \
4272 duk_push_int((ctx), (duk_int_t) (val))
4273
4274/* sometimes stack and array indices need to go on the stack */
4275#define duk_push_idx(ctx,val) \
4276 duk_push_int((ctx), (duk_int_t) (val))
4277#define duk_push_uarridx(ctx,val) \
4278 duk_push_uint((ctx), (duk_uint_t) (val))
4279#define duk_push_size_t(ctx,val) \
4280 duk_push_uint((ctx), (duk_uint_t) (val)) /* XXX: assumed to fit for now */
4281
7c673cae
FG
4282DUK_INTERNAL_DECL duk_hstring *duk_get_hstring(duk_context *ctx, duk_idx_t index);
4283DUK_INTERNAL_DECL duk_hobject *duk_get_hobject(duk_context *ctx, duk_idx_t index);
4284DUK_INTERNAL_DECL duk_hbuffer *duk_get_hbuffer(duk_context *ctx, duk_idx_t index);
4285DUK_INTERNAL_DECL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t index);
4286DUK_INTERNAL_DECL duk_hcompiledfunction *duk_get_hcompiledfunction(duk_context *ctx, duk_idx_t index);
4287DUK_INTERNAL_DECL duk_hnativefunction *duk_get_hnativefunction(duk_context *ctx, duk_idx_t index);
4288
11fdf7f2 4289DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum);
7c673cae
FG
4290
4291#if 0 /* This would be pointless: unexpected type and lightfunc would both return NULL */
4292DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_or_lfunc(duk_context *ctx, duk_idx_t index);
4293#endif
4294DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index);
4295
4296#if 0 /*unused*/
4297DUK_INTERNAL_DECL void *duk_get_voidptr(duk_context *ctx, duk_idx_t index);
4298#endif
4299
4300DUK_INTERNAL_DECL duk_hstring *duk_to_hstring(duk_context *ctx, duk_idx_t index);
11fdf7f2
TL
4301#if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */
4302DUK_INTERNAL_DECL duk_hstring *duk_safe_to_hstring(duk_context *ctx, duk_idx_t index);
4303#endif
4304DUK_INTERNAL_DECL void duk_to_object_class_string_top(duk_context *ctx);
4305#if !defined(DUK_USE_PARANOID_ERRORS)
4306DUK_INTERNAL_DECL void duk_push_hobject_class_string(duk_context *ctx, duk_hobject *h);
4307#endif
4308
7c673cae
FG
4309DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped); /* out_clamped=NULL, RangeError if outside range */
4310DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval);
4311DUK_INTERNAL_DECL duk_int_t duk_to_int_check_range(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval);
4312#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
4313DUK_INTERNAL_DECL duk_uint8_t duk_to_uint8clamped(duk_context *ctx, duk_idx_t index);
4314#endif
4315
4316DUK_INTERNAL_DECL duk_hstring *duk_require_hstring(duk_context *ctx, duk_idx_t index);
4317DUK_INTERNAL_DECL duk_hobject *duk_require_hobject(duk_context *ctx, duk_idx_t index);
4318DUK_INTERNAL_DECL duk_hbuffer *duk_require_hbuffer(duk_context *ctx, duk_idx_t index);
4319DUK_INTERNAL_DECL duk_hthread *duk_require_hthread(duk_context *ctx, duk_idx_t index);
4320DUK_INTERNAL_DECL duk_hcompiledfunction *duk_require_hcompiledfunction(duk_context *ctx, duk_idx_t index);
4321DUK_INTERNAL_DECL duk_hnativefunction *duk_require_hnativefunction(duk_context *ctx, duk_idx_t index);
4322
11fdf7f2 4323DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum);
7c673cae
FG
4324
4325DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_or_lfunc(duk_context *ctx, duk_idx_t index);
4326DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index);
4327
7c673cae
FG
4328DUK_INTERNAL_DECL void duk_push_hstring(duk_context *ctx, duk_hstring *h);
4329DUK_INTERNAL_DECL void duk_push_hstring_stridx(duk_context *ctx, duk_small_int_t stridx);
4330DUK_INTERNAL_DECL void duk_push_hobject(duk_context *ctx, duk_hobject *h);
4331DUK_INTERNAL_DECL void duk_push_hbuffer(duk_context *ctx, duk_hbuffer *h);
4332#define duk_push_hthread(ctx,h) \
4333 duk_push_hobject((ctx), (duk_hobject *) (h))
4334#define duk_push_hcompiledfunction(ctx,h) \
4335 duk_push_hobject((ctx), (duk_hobject *) (h))
4336#define duk_push_hnativefunction(ctx,h) \
4337 duk_push_hobject((ctx), (duk_hobject *) (h))
4338DUK_INTERNAL_DECL void duk_push_hobject_bidx(duk_context *ctx, duk_small_int_t builtin_idx);
4339DUK_INTERNAL_DECL duk_idx_t duk_push_object_helper(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx);
4340DUK_INTERNAL_DECL duk_idx_t duk_push_object_helper_proto(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_hobject *proto);
4341DUK_INTERNAL_DECL duk_idx_t duk_push_object_internal(duk_context *ctx);
4342DUK_INTERNAL_DECL duk_idx_t duk_push_compiledfunction(duk_context *ctx);
4343DUK_INTERNAL_DECL void duk_push_c_function_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs);
4344DUK_INTERNAL_DECL void duk_push_c_function_noconstruct_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs);
4345
4346DUK_INTERNAL_DECL void duk_push_string_funcptr(duk_context *ctx, duk_uint8_t *ptr, duk_size_t sz);
4347DUK_INTERNAL_DECL void duk_push_lightfunc_name(duk_context *ctx, duk_tval *tv);
4348DUK_INTERNAL_DECL void duk_push_lightfunc_tostring(duk_context *ctx, duk_tval *tv);
4349DUK_INTERNAL_DECL duk_hbufferobject *duk_push_bufferobject_raw(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx);
4350
11fdf7f2
TL
4351#if !defined(DUK_USE_PARANOID_ERRORS)
4352DUK_INTERNAL_DECL const char *duk_push_string_readable(duk_context *ctx, duk_idx_t index);
4353DUK_INTERNAL_DECL const char *duk_push_string_tval_readable(duk_context *ctx, duk_tval *tv);
4354#endif
4355
7c673cae
FG
4356DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [] -> [val] */
4357DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [val] -> [] */
4358DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [] -> [] */
4359DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [] -> [] */
4360
4361DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx_boolean(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_bool_t *out_has_prop); /* [] -> [] */
4362
4363DUK_INTERNAL_DECL void duk_xdef_prop(duk_context *ctx, duk_idx_t obj_index, duk_small_uint_t desc_flags); /* [key val] -> [] */
4364DUK_INTERNAL_DECL void duk_xdef_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index, duk_small_uint_t desc_flags); /* [val] -> [] */
4365DUK_INTERNAL_DECL void duk_xdef_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags); /* [val] -> [] */
4366DUK_INTERNAL_DECL void duk_xdef_prop_stridx_builtin(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags); /* [] -> [] */
4367DUK_INTERNAL_DECL void duk_xdef_prop_stridx_thrower(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags); /* [] -> [] */
4368
4369/* These are macros for now, but could be separate functions to reduce code
4370 * footprint (check call site count before refactoring).
4371 */
4372#define duk_xdef_prop_wec(ctx,obj_index) \
4373 duk_xdef_prop((ctx), (obj_index), DUK_PROPDESC_FLAGS_WEC)
4374#define duk_xdef_prop_index_wec(ctx,obj_index,arr_index) \
4375 duk_xdef_prop_index((ctx), (obj_index), (arr_index), DUK_PROPDESC_FLAGS_WEC)
4376#define duk_xdef_prop_stridx_wec(ctx,obj_index,stridx) \
4377 duk_xdef_prop_stridx((ctx), (obj_index), (stridx), DUK_PROPDESC_FLAGS_WEC)
4378
4379/* Set object 'length'. */
4380DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_size_t length);
4381
11fdf7f2
TL
4382/* Raw internal valstack access macros: access is unsafe so call site
4383 * must have a guarantee that the index is valid. When that is the case,
4384 * using these macro results in faster and smaller code than duk_get_tval().
4385 * Both 'ctx' and 'idx' are evaluted multiple times, but only for asserts.
4386 */
4387#define DUK_ASSERT_VALID_NEGIDX(ctx,idx) \
4388 (DUK_ASSERT_EXPR((idx) < 0), DUK_ASSERT_EXPR(duk_is_valid_index((ctx), (idx))))
4389#define DUK_ASSERT_VALID_POSIDX(ctx,idx) \
4390 (DUK_ASSERT_EXPR((idx) >= 0), DUK_ASSERT_EXPR(duk_is_valid_index((ctx), (idx))))
4391#define DUK_GET_TVAL_NEGIDX(ctx,idx) \
4392 (DUK_ASSERT_VALID_NEGIDX((ctx),(idx)), ((duk_hthread *) (ctx))->valstack_top + (idx))
4393#define DUK_GET_TVAL_POSIDX(ctx,idx) \
4394 (DUK_ASSERT_VALID_POSIDX((ctx),(idx)), ((duk_hthread *) (ctx))->valstack_bottom + (idx))
4395#define DUK_GET_HOBJECT_NEGIDX(ctx,idx) \
4396 (DUK_ASSERT_VALID_NEGIDX((ctx),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (ctx))->valstack_top + (idx)))
4397#define DUK_GET_HOBJECT_POSIDX(ctx,idx) \
4398 (DUK_ASSERT_VALID_POSIDX((ctx),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (ctx))->valstack_bottom + (idx)))
4399
7c673cae 4400#endif /* DUK_API_INTERNAL_H_INCLUDED */
7c673cae
FG
4401/*
4402 * Heap string representation.
4403 *
4404 * Strings are byte sequences ordinarily stored in extended UTF-8 format,
4405 * allowing values larger than the official UTF-8 range (used internally)
4406 * and also allowing UTF-8 encoding of surrogate pairs (CESU-8 format).
4407 * Strings may also be invalid UTF-8 altogether which is the case e.g. with
4408 * strings used as internal property names and raw buffers converted to
4409 * strings. In such cases the 'clen' field contains an inaccurate value.
4410 *
4411 * Ecmascript requires support for 32-bit long strings. However, since each
4412 * 16-bit codepoint can take 3 bytes in CESU-8, this representation can only
4413 * support about 1.4G codepoint long strings in extreme cases. This is not
4414 * really a practical issue.
4415 */
4416
4417#ifndef DUK_HSTRING_H_INCLUDED
4418#define DUK_HSTRING_H_INCLUDED
4419
4420/* Impose a maximum string length for now. Restricted artificially to
4421 * ensure adding a heap header length won't overflow size_t. The limit
4422 * should be synchronized with DUK_HBUFFER_MAX_BYTELEN.
4423 *
4424 * E5.1 makes provisions to support strings longer than 4G characters.
4425 * This limit should be eliminated on 64-bit platforms (and increased
4426 * closer to maximum support on 32-bit platforms).
4427 */
4428
4429#if defined(DUK_USE_STRLEN16)
4430#define DUK_HSTRING_MAX_BYTELEN (0x0000ffffUL)
4431#else
4432#define DUK_HSTRING_MAX_BYTELEN (0x7fffffffUL)
4433#endif
4434
4435/* XXX: could add flags for "is valid CESU-8" (Ecmascript compatible strings),
4436 * "is valid UTF-8", "is valid extended UTF-8" (internal strings are not,
4437 * regexp bytecode is), and "contains non-BMP characters". These are not
4438 * needed right now.
4439 */
4440
11fdf7f2
TL
4441#define DUK_HSTRING_FLAG_ASCII DUK_HEAPHDR_USER_FLAG(0) /* string is ASCII, clen == blen */
4442#define DUK_HSTRING_FLAG_ARRIDX DUK_HEAPHDR_USER_FLAG(1) /* string is a valid array index */
4443#define DUK_HSTRING_FLAG_INTERNAL DUK_HEAPHDR_USER_FLAG(2) /* string is internal */
4444#define DUK_HSTRING_FLAG_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(3) /* string is a reserved word (non-strict) */
4445#define DUK_HSTRING_FLAG_STRICT_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(4) /* string is a reserved word (strict) */
4446#define DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS DUK_HEAPHDR_USER_FLAG(5) /* string is 'eval' or 'arguments' */
4447#define DUK_HSTRING_FLAG_EXTDATA DUK_HEAPHDR_USER_FLAG(6) /* string data is external (duk_hstring_external) */
7c673cae 4448
11fdf7f2 4449#define DUK_HSTRING_HAS_ASCII(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII)
7c673cae
FG
4450#define DUK_HSTRING_HAS_ARRIDX(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
4451#define DUK_HSTRING_HAS_INTERNAL(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_INTERNAL)
4452#define DUK_HSTRING_HAS_RESERVED_WORD(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD)
4453#define DUK_HSTRING_HAS_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
4454#define DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
4455#define DUK_HSTRING_HAS_EXTDATA(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA)
4456
11fdf7f2 4457#define DUK_HSTRING_SET_ASCII(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII)
7c673cae
FG
4458#define DUK_HSTRING_SET_ARRIDX(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
4459#define DUK_HSTRING_SET_INTERNAL(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_INTERNAL)
4460#define DUK_HSTRING_SET_RESERVED_WORD(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD)
4461#define DUK_HSTRING_SET_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
4462#define DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
4463#define DUK_HSTRING_SET_EXTDATA(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA)
4464
11fdf7f2 4465#define DUK_HSTRING_CLEAR_ASCII(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII)
7c673cae
FG
4466#define DUK_HSTRING_CLEAR_ARRIDX(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
4467#define DUK_HSTRING_CLEAR_INTERNAL(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_INTERNAL)
4468#define DUK_HSTRING_CLEAR_RESERVED_WORD(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD)
4469#define DUK_HSTRING_CLEAR_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
4470#define DUK_HSTRING_CLEAR_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
4471#define DUK_HSTRING_CLEAR_EXTDATA(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA)
4472
11fdf7f2
TL
4473#if 0 /* Slightly smaller code without explicit flag, but explicit flag
4474 * is very useful when 'clen' is dropped.
4475 */
7c673cae 4476#define DUK_HSTRING_IS_ASCII(x) (DUK_HSTRING_GET_BYTELEN((x)) == DUK_HSTRING_GET_CHARLEN((x)))
11fdf7f2
TL
4477#endif
4478#define DUK_HSTRING_IS_ASCII(x) DUK_HSTRING_HAS_ASCII((x))
7c673cae
FG
4479#define DUK_HSTRING_IS_EMPTY(x) (DUK_HSTRING_GET_BYTELEN((x)) == 0)
4480
4481#if defined(DUK_USE_STRHASH16)
4482#define DUK_HSTRING_GET_HASH(x) ((x)->hdr.h_flags >> 16)
4483#define DUK_HSTRING_SET_HASH(x,v) do { \
4484 (x)->hdr.h_flags = ((x)->hdr.h_flags & 0x0000ffffUL) | ((v) << 16); \
4485 } while (0)
4486#else
4487#define DUK_HSTRING_GET_HASH(x) ((x)->hash)
4488#define DUK_HSTRING_SET_HASH(x,v) do { \
4489 (x)->hash = (v); \
4490 } while (0)
4491#endif
4492
4493#if defined(DUK_USE_STRLEN16)
11fdf7f2 4494#define DUK_HSTRING_GET_BYTELEN(x) ((x)->hdr.h_strextra16)
7c673cae 4495#define DUK_HSTRING_SET_BYTELEN(x,v) do { \
11fdf7f2 4496 (x)->hdr.h_strextra16 = (v); \
7c673cae 4497 } while (0)
11fdf7f2 4498#if defined(DUK_USE_HSTRING_CLEN)
7c673cae
FG
4499#define DUK_HSTRING_GET_CHARLEN(x) ((x)->clen16)
4500#define DUK_HSTRING_SET_CHARLEN(x,v) do { \
4501 (x)->clen16 = (v); \
4502 } while (0)
4503#else
11fdf7f2
TL
4504#define DUK_HSTRING_GET_CHARLEN(x) duk_hstring_get_charlen((x))
4505#define DUK_HSTRING_SET_CHARLEN(x,v) do { \
4506 DUK_ASSERT(0); /* should never be called */ \
4507 } while (0)
4508#endif
4509#else
7c673cae
FG
4510#define DUK_HSTRING_GET_BYTELEN(x) ((x)->blen)
4511#define DUK_HSTRING_SET_BYTELEN(x,v) do { \
4512 (x)->blen = (v); \
4513 } while (0)
4514#define DUK_HSTRING_GET_CHARLEN(x) ((x)->clen)
4515#define DUK_HSTRING_SET_CHARLEN(x,v) do { \
4516 (x)->clen = (v); \
4517 } while (0)
4518#endif
4519
4520#if defined(DUK_USE_HSTRING_EXTDATA)
4521#define DUK_HSTRING_GET_EXTDATA(x) \
4522 ((x)->extdata)
4523#define DUK_HSTRING_GET_DATA(x) \
4524 (DUK_HSTRING_HAS_EXTDATA((x)) ? \
11fdf7f2 4525 DUK_HSTRING_GET_EXTDATA((const duk_hstring_external *) (x)) : ((const duk_uint8_t *) ((x) + 1)))
7c673cae
FG
4526#else
4527#define DUK_HSTRING_GET_DATA(x) \
4528 ((const duk_uint8_t *) ((x) + 1))
4529#endif
4530
4531#define DUK_HSTRING_GET_DATA_END(x) \
4532 (DUK_HSTRING_GET_DATA((x)) + (x)->blen)
4533
4534/* marker value; in E5 2^32-1 is not a valid array index (2^32-2 is highest valid) */
4535#define DUK_HSTRING_NO_ARRAY_INDEX (0xffffffffUL)
4536
4537/* get array index related to string (or return DUK_HSTRING_NO_ARRAY_INDEX);
4538 * avoids helper call if string has no array index value.
4539 */
4540#define DUK_HSTRING_GET_ARRIDX_FAST(h) \
4541 (DUK_HSTRING_HAS_ARRIDX((h)) ? duk_js_to_arrayindex_string_helper((h)) : DUK_HSTRING_NO_ARRAY_INDEX)
4542
4543/* slower but more compact variant */
4544#define DUK_HSTRING_GET_ARRIDX_SLOW(h) \
4545 (duk_js_to_arrayindex_string_helper((h)))
4546
4547/*
4548 * Misc
4549 */
4550
4551struct duk_hstring {
4552 /* Smaller heaphdr than for other objects, because strings are held
4553 * in string intern table which requires no link pointers. Much of
4554 * the 32-bit flags field is unused by flags, so we can stuff a 16-bit
4555 * field in there.
4556 */
4557 duk_heaphdr_string hdr;
4558
4559 /* Note: we could try to stuff a partial hash (e.g. 16 bits) into the
4560 * shared heap header. Good hashing needs more hash bits though.
4561 */
4562
4563 /* string hash */
4564#if defined(DUK_USE_STRHASH16)
4565 /* If 16-bit hash is in use, stuff it into duk_heaphdr_string flags. */
4566#else
4567 duk_uint32_t hash;
4568#endif
4569
4570 /* length in bytes (not counting NUL term) */
4571#if defined(DUK_USE_STRLEN16)
11fdf7f2 4572 /* placed in duk_heaphdr_string */
7c673cae
FG
4573#else
4574 duk_uint32_t blen;
4575#endif
4576
4577 /* length in codepoints (must be E5 compatible) */
4578#if defined(DUK_USE_STRLEN16)
11fdf7f2 4579#if defined(DUK_USE_HSTRING_CLEN)
7c673cae 4580 duk_uint16_t clen16;
11fdf7f2
TL
4581#else
4582 /* computed live */
4583#endif
7c673cae
FG
4584#else
4585 duk_uint32_t clen;
4586#endif
4587
4588 /*
4589 * String value of 'blen+1' bytes follows (+1 for NUL termination
4590 * convenience for C API). No alignment needs to be guaranteed
4591 * for strings, but fields above should guarantee alignment-by-4
4592 * (but not alignment-by-8).
4593 */
4594};
4595
4596/* The external string struct is defined even when the feature is inactive. */
4597struct duk_hstring_external {
4598 duk_hstring str;
4599
4600 /*
4601 * For an external string, the NUL-terminated string data is stored
4602 * externally. The user must guarantee that data behind this pointer
4603 * doesn't change while it's used.
4604 */
4605
4606 const duk_uint8_t *extdata;
4607};
4608
4609/*
4610 * Prototypes
4611 */
4612
4613DUK_INTERNAL_DECL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos);
4614
11fdf7f2
TL
4615#if !defined(DUK_USE_HSTRING_CLEN)
4616DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
4617#endif
4618
7c673cae 4619#endif /* DUK_HSTRING_H_INCLUDED */
7c673cae
FG
4620/*
4621 * Heap object representation.
4622 *
4623 * Heap objects are used for Ecmascript objects, arrays, and functions,
4624 * but also for internal control like declarative and object environment
4625 * records. Compiled functions, native functions, and threads are also
4626 * objects but with an extended C struct.
4627 *
4628 * Objects provide the required Ecmascript semantics and exotic behaviors
4629 * especially for property access.
4630 *
4631 * Properties are stored in three conceptual parts:
4632 *
4633 * 1. A linear 'entry part' contains ordered key-value-attributes triples
4634 * and is the main method of string properties.
4635 *
4636 * 2. An optional linear 'array part' is used for array objects to store a
4637 * (dense) range of [0,N[ array indexed entries with default attributes
4638 * (writable, enumerable, configurable). If the array part would become
4639 * sparse or non-default attributes are required, the array part is
4640 * abandoned and moved to the 'entry part'.
4641 *
4642 * 3. An optional 'hash part' is used to optimize lookups of the entry
4643 * part; it is used only for objects with sufficiently many properties
4644 * and can be abandoned without loss of information.
4645 *
4646 * These three conceptual parts are stored in a single memory allocated area.
4647 * This minimizes memory allocation overhead but also means that all three
4648 * parts are resized together, and makes property access a bit complicated.
4649 */
4650
4651#ifndef DUK_HOBJECT_H_INCLUDED
4652#define DUK_HOBJECT_H_INCLUDED
4653
11fdf7f2
TL
4654/* Object flag. There are currently 26 flag bits available. Make sure
4655 * this stays in sync with debugger object inspection code.
4656 */
7c673cae
FG
4657#define DUK_HOBJECT_FLAG_EXTENSIBLE DUK_HEAPHDR_USER_FLAG(0) /* object is extensible */
4658#define DUK_HOBJECT_FLAG_CONSTRUCTABLE DUK_HEAPHDR_USER_FLAG(1) /* object is constructable */
4659#define DUK_HOBJECT_FLAG_BOUND DUK_HEAPHDR_USER_FLAG(2) /* object established using Function.prototype.bind() */
4660#define DUK_HOBJECT_FLAG_COMPILEDFUNCTION DUK_HEAPHDR_USER_FLAG(4) /* object is a compiled function (duk_hcompiledfunction) */
4661#define DUK_HOBJECT_FLAG_NATIVEFUNCTION DUK_HEAPHDR_USER_FLAG(5) /* object is a native function (duk_hnativefunction) */
4662#define DUK_HOBJECT_FLAG_BUFFEROBJECT DUK_HEAPHDR_USER_FLAG(6) /* object is a buffer object (duk_hbufferobject) (always exotic) */
4663#define DUK_HOBJECT_FLAG_THREAD DUK_HEAPHDR_USER_FLAG(7) /* object is a thread (duk_hthread) */
4664#define DUK_HOBJECT_FLAG_ARRAY_PART DUK_HEAPHDR_USER_FLAG(8) /* object has an array part (a_size may still be 0) */
4665#define DUK_HOBJECT_FLAG_STRICT DUK_HEAPHDR_USER_FLAG(9) /* function: function object is strict */
4666#define DUK_HOBJECT_FLAG_NOTAIL DUK_HEAPHDR_USER_FLAG(10) /* function: function must not be tail called */
4667#define DUK_HOBJECT_FLAG_NEWENV DUK_HEAPHDR_USER_FLAG(11) /* function: create new environment when called (see duk_hcompiledfunction) */
4668#define DUK_HOBJECT_FLAG_NAMEBINDING DUK_HEAPHDR_USER_FLAG(12) /* function: create binding for func name (function templates only, used for named function expressions) */
4669#define DUK_HOBJECT_FLAG_CREATEARGS DUK_HEAPHDR_USER_FLAG(13) /* function: create an arguments object on function call */
4670#define DUK_HOBJECT_FLAG_ENVRECCLOSED DUK_HEAPHDR_USER_FLAG(14) /* envrec: (declarative) record is closed */
4671#define DUK_HOBJECT_FLAG_EXOTIC_ARRAY DUK_HEAPHDR_USER_FLAG(15) /* 'Array' object, array length and index exotic behavior */
4672#define DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ DUK_HEAPHDR_USER_FLAG(16) /* 'String' object, array index exotic behavior */
4673#define DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS DUK_HEAPHDR_USER_FLAG(17) /* 'Arguments' object and has arguments exotic behavior (non-strict callee) */
4674#define DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC DUK_HEAPHDR_USER_FLAG(18) /* Duktape/C (nativefunction) object, exotic 'length' */
4675#define DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ DUK_HEAPHDR_USER_FLAG(19) /* 'Proxy' object */
4676
11fdf7f2 4677#define DUK_HOBJECT_FLAG_CLASS_BASE DUK_HEAPHDR_USER_FLAG_NUMBER(20)
7c673cae
FG
4678#define DUK_HOBJECT_FLAG_CLASS_BITS 5
4679
4680#define DUK_HOBJECT_GET_CLASS_NUMBER(h) \
4681 DUK_HEAPHDR_GET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS)
4682#define DUK_HOBJECT_SET_CLASS_NUMBER(h,v) \
4683 DUK_HEAPHDR_SET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS, (v))
4684
4685#define DUK_HOBJECT_GET_CLASS_MASK(h) \
4686 (1UL << DUK_HEAPHDR_GET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS))
4687
4688/* Macro for creating flag initializer from a class number.
4689 * Unsigned type cast is needed to avoid warnings about coercing
4690 * a signed integer to an unsigned one; the largest class values
4691 * have the highest bit (bit 31) set which causes this.
4692 */
4693#define DUK_HOBJECT_CLASS_AS_FLAGS(v) (((duk_uint_t) (v)) << DUK_HOBJECT_FLAG_CLASS_BASE)
4694
4695/* E5 Section 8.6.2 + custom classes */
4696#define DUK_HOBJECT_CLASS_UNUSED 0
4697#define DUK_HOBJECT_CLASS_ARGUMENTS 1
4698#define DUK_HOBJECT_CLASS_ARRAY 2
4699#define DUK_HOBJECT_CLASS_BOOLEAN 3
4700#define DUK_HOBJECT_CLASS_DATE 4
4701#define DUK_HOBJECT_CLASS_ERROR 5
4702#define DUK_HOBJECT_CLASS_FUNCTION 6
4703#define DUK_HOBJECT_CLASS_JSON 7
4704#define DUK_HOBJECT_CLASS_MATH 8
4705#define DUK_HOBJECT_CLASS_NUMBER 9
4706#define DUK_HOBJECT_CLASS_OBJECT 10
4707#define DUK_HOBJECT_CLASS_REGEXP 11
4708#define DUK_HOBJECT_CLASS_STRING 12
4709#define DUK_HOBJECT_CLASS_GLOBAL 13
4710#define DUK_HOBJECT_CLASS_OBJENV 14 /* custom */
4711#define DUK_HOBJECT_CLASS_DECENV 15 /* custom */
4712#define DUK_HOBJECT_CLASS_BUFFER 16 /* custom; implies DUK_HOBJECT_IS_BUFFEROBJECT */
4713#define DUK_HOBJECT_CLASS_POINTER 17 /* custom */
4714#define DUK_HOBJECT_CLASS_THREAD 18 /* custom; implies DUK_HOBJECT_IS_THREAD */
4715#define DUK_HOBJECT_CLASS_ARRAYBUFFER 19 /* implies DUK_HOBJECT_IS_BUFFEROBJECT */
4716#define DUK_HOBJECT_CLASS_DATAVIEW 20
4717#define DUK_HOBJECT_CLASS_INT8ARRAY 21
4718#define DUK_HOBJECT_CLASS_UINT8ARRAY 22
4719#define DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY 23
4720#define DUK_HOBJECT_CLASS_INT16ARRAY 24
4721#define DUK_HOBJECT_CLASS_UINT16ARRAY 25
4722#define DUK_HOBJECT_CLASS_INT32ARRAY 26
4723#define DUK_HOBJECT_CLASS_UINT32ARRAY 27
4724#define DUK_HOBJECT_CLASS_FLOAT32ARRAY 28
4725#define DUK_HOBJECT_CLASS_FLOAT64ARRAY 29
4726#define DUK_HOBJECT_CLASS_MAX 29
4727
4728/* class masks */
4729#define DUK_HOBJECT_CMASK_ALL ((1UL << (DUK_HOBJECT_CLASS_MAX + 1)) - 1UL)
4730#define DUK_HOBJECT_CMASK_UNUSED (1UL << DUK_HOBJECT_CLASS_UNUSED)
4731#define DUK_HOBJECT_CMASK_ARGUMENTS (1UL << DUK_HOBJECT_CLASS_ARGUMENTS)
4732#define DUK_HOBJECT_CMASK_ARRAY (1UL << DUK_HOBJECT_CLASS_ARRAY)
4733#define DUK_HOBJECT_CMASK_BOOLEAN (1UL << DUK_HOBJECT_CLASS_BOOLEAN)
4734#define DUK_HOBJECT_CMASK_DATE (1UL << DUK_HOBJECT_CLASS_DATE)
4735#define DUK_HOBJECT_CMASK_ERROR (1UL << DUK_HOBJECT_CLASS_ERROR)
4736#define DUK_HOBJECT_CMASK_FUNCTION (1UL << DUK_HOBJECT_CLASS_FUNCTION)
4737#define DUK_HOBJECT_CMASK_JSON (1UL << DUK_HOBJECT_CLASS_JSON)
4738#define DUK_HOBJECT_CMASK_MATH (1UL << DUK_HOBJECT_CLASS_MATH)
4739#define DUK_HOBJECT_CMASK_NUMBER (1UL << DUK_HOBJECT_CLASS_NUMBER)
4740#define DUK_HOBJECT_CMASK_OBJECT (1UL << DUK_HOBJECT_CLASS_OBJECT)
4741#define DUK_HOBJECT_CMASK_REGEXP (1UL << DUK_HOBJECT_CLASS_REGEXP)
4742#define DUK_HOBJECT_CMASK_STRING (1UL << DUK_HOBJECT_CLASS_STRING)
4743#define DUK_HOBJECT_CMASK_GLOBAL (1UL << DUK_HOBJECT_CLASS_GLOBAL)
4744#define DUK_HOBJECT_CMASK_OBJENV (1UL << DUK_HOBJECT_CLASS_OBJENV)
4745#define DUK_HOBJECT_CMASK_DECENV (1UL << DUK_HOBJECT_CLASS_DECENV)
4746#define DUK_HOBJECT_CMASK_BUFFER (1UL << DUK_HOBJECT_CLASS_BUFFER)
4747#define DUK_HOBJECT_CMASK_POINTER (1UL << DUK_HOBJECT_CLASS_POINTER)
4748#define DUK_HOBJECT_CMASK_THREAD (1UL << DUK_HOBJECT_CLASS_THREAD)
4749#define DUK_HOBJECT_CMASK_ARRAYBUFFER (1UL << DUK_HOBJECT_CLASS_ARRAYBUFFER)
4750#define DUK_HOBJECT_CMASK_DATAVIEW (1UL << DUK_HOBJECT_CLASS_DATAVIEW)
4751#define DUK_HOBJECT_CMASK_INT8ARRAY (1UL << DUK_HOBJECT_CLASS_INT8ARRAY)
4752#define DUK_HOBJECT_CMASK_UINT8ARRAY (1UL << DUK_HOBJECT_CLASS_UINT8ARRAY)
4753#define DUK_HOBJECT_CMASK_UINT8CLAMPEDARRAY (1UL << DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY)
4754#define DUK_HOBJECT_CMASK_INT16ARRAY (1UL << DUK_HOBJECT_CLASS_INT16ARRAY)
4755#define DUK_HOBJECT_CMASK_UINT16ARRAY (1UL << DUK_HOBJECT_CLASS_UINT16ARRAY)
4756#define DUK_HOBJECT_CMASK_INT32ARRAY (1UL << DUK_HOBJECT_CLASS_INT32ARRAY)
4757#define DUK_HOBJECT_CMASK_UINT32ARRAY (1UL << DUK_HOBJECT_CLASS_UINT32ARRAY)
4758#define DUK_HOBJECT_CMASK_FLOAT32ARRAY (1UL << DUK_HOBJECT_CLASS_FLOAT32ARRAY)
4759#define DUK_HOBJECT_CMASK_FLOAT64ARRAY (1UL << DUK_HOBJECT_CLASS_FLOAT64ARRAY)
4760
4761#define DUK_HOBJECT_CMASK_ALL_BUFFEROBJECTS \
4762 (DUK_HOBJECT_CMASK_BUFFER | \
4763 DUK_HOBJECT_CMASK_ARRAYBUFFER | \
4764 DUK_HOBJECT_CMASK_DATAVIEW | \
4765 DUK_HOBJECT_CMASK_INT8ARRAY | \
4766 DUK_HOBJECT_CMASK_UINT8ARRAY | \
4767 DUK_HOBJECT_CMASK_UINT8CLAMPEDARRAY | \
4768 DUK_HOBJECT_CMASK_INT16ARRAY | \
4769 DUK_HOBJECT_CMASK_UINT16ARRAY | \
4770 DUK_HOBJECT_CMASK_INT32ARRAY | \
4771 DUK_HOBJECT_CMASK_UINT32ARRAY | \
4772 DUK_HOBJECT_CMASK_FLOAT32ARRAY | \
4773 DUK_HOBJECT_CMASK_FLOAT64ARRAY)
4774
4775#define DUK_HOBJECT_IS_OBJENV(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_OBJENV)
4776#define DUK_HOBJECT_IS_DECENV(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_DECENV)
4777#define DUK_HOBJECT_IS_ENV(h) (DUK_HOBJECT_IS_OBJENV((h)) || DUK_HOBJECT_IS_DECENV((h)))
4778#define DUK_HOBJECT_IS_ARRAY(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAY)
4779#define DUK_HOBJECT_IS_COMPILEDFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION)
4780#define DUK_HOBJECT_IS_NATIVEFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION)
4781#define DUK_HOBJECT_IS_BUFFEROBJECT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT)
4782#define DUK_HOBJECT_IS_THREAD(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
4783
4784#define DUK_HOBJECT_IS_NONBOUND_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
4785 DUK_HOBJECT_FLAG_COMPILEDFUNCTION | \
4786 DUK_HOBJECT_FLAG_NATIVEFUNCTION)
4787
4788#define DUK_HOBJECT_IS_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
4789 DUK_HOBJECT_FLAG_BOUND | \
4790 DUK_HOBJECT_FLAG_COMPILEDFUNCTION | \
4791 DUK_HOBJECT_FLAG_NATIVEFUNCTION)
4792
4793#define DUK_HOBJECT_IS_CALLABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
4794 DUK_HOBJECT_FLAG_BOUND | \
4795 DUK_HOBJECT_FLAG_COMPILEDFUNCTION | \
4796 DUK_HOBJECT_FLAG_NATIVEFUNCTION)
4797
4798/* object has any exotic behavior(s) */
4799#define DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS (DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \
4800 DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS | \
4801 DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | \
4802 DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC | \
4803 DUK_HOBJECT_FLAG_BUFFEROBJECT | \
4804 DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
4805
4806#define DUK_HOBJECT_HAS_EXOTIC_BEHAVIOR(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS)
4807
4808#define DUK_HOBJECT_HAS_EXTENSIBLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
4809#define DUK_HOBJECT_HAS_CONSTRUCTABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
4810#define DUK_HOBJECT_HAS_BOUND(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUND)
4811#define DUK_HOBJECT_HAS_COMPILEDFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION)
4812#define DUK_HOBJECT_HAS_NATIVEFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION)
4813#define DUK_HOBJECT_HAS_BUFFEROBJECT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT)
4814#define DUK_HOBJECT_HAS_THREAD(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
4815#define DUK_HOBJECT_HAS_ARRAY_PART(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
4816#define DUK_HOBJECT_HAS_STRICT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
4817#define DUK_HOBJECT_HAS_NOTAIL(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
4818#define DUK_HOBJECT_HAS_NEWENV(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
4819#define DUK_HOBJECT_HAS_NAMEBINDING(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
4820#define DUK_HOBJECT_HAS_CREATEARGS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
4821#define DUK_HOBJECT_HAS_ENVRECCLOSED(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED)
4822#define DUK_HOBJECT_HAS_EXOTIC_ARRAY(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
4823#define DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
4824#define DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
4825#define DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC)
4826#define DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
4827
4828#define DUK_HOBJECT_SET_EXTENSIBLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
4829#define DUK_HOBJECT_SET_CONSTRUCTABLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
4830#define DUK_HOBJECT_SET_BOUND(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUND)
4831#define DUK_HOBJECT_SET_COMPILEDFUNCTION(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION)
4832#define DUK_HOBJECT_SET_NATIVEFUNCTION(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION)
4833#define DUK_HOBJECT_SET_BUFFEROBJECT(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT)
4834#define DUK_HOBJECT_SET_THREAD(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
4835#define DUK_HOBJECT_SET_ARRAY_PART(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
4836#define DUK_HOBJECT_SET_STRICT(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
4837#define DUK_HOBJECT_SET_NOTAIL(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
4838#define DUK_HOBJECT_SET_NEWENV(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
4839#define DUK_HOBJECT_SET_NAMEBINDING(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
4840#define DUK_HOBJECT_SET_CREATEARGS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
4841#define DUK_HOBJECT_SET_ENVRECCLOSED(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED)
4842#define DUK_HOBJECT_SET_EXOTIC_ARRAY(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
4843#define DUK_HOBJECT_SET_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
4844#define DUK_HOBJECT_SET_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
4845#define DUK_HOBJECT_SET_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC)
4846#define DUK_HOBJECT_SET_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
4847
4848#define DUK_HOBJECT_CLEAR_EXTENSIBLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
4849#define DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
4850#define DUK_HOBJECT_CLEAR_BOUND(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUND)
4851#define DUK_HOBJECT_CLEAR_COMPILEDFUNCTION(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION)
4852#define DUK_HOBJECT_CLEAR_NATIVEFUNCTION(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION)
4853#define DUK_HOBJECT_CLEAR_BUFFEROBJECT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT)
4854#define DUK_HOBJECT_CLEAR_THREAD(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
4855#define DUK_HOBJECT_CLEAR_ARRAY_PART(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
4856#define DUK_HOBJECT_CLEAR_STRICT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
4857#define DUK_HOBJECT_CLEAR_NOTAIL(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
4858#define DUK_HOBJECT_CLEAR_NEWENV(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
4859#define DUK_HOBJECT_CLEAR_NAMEBINDING(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
4860#define DUK_HOBJECT_CLEAR_CREATEARGS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
4861#define DUK_HOBJECT_CLEAR_ENVRECCLOSED(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED)
4862#define DUK_HOBJECT_CLEAR_EXOTIC_ARRAY(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
4863#define DUK_HOBJECT_CLEAR_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
4864#define DUK_HOBJECT_CLEAR_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
4865#define DUK_HOBJECT_CLEAR_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC)
4866#define DUK_HOBJECT_CLEAR_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
4867
4868/* flags used for property attributes in duk_propdesc and packed flags */
4869#define DUK_PROPDESC_FLAG_WRITABLE (1 << 0) /* E5 Section 8.6.1 */
4870#define DUK_PROPDESC_FLAG_ENUMERABLE (1 << 1) /* E5 Section 8.6.1 */
4871#define DUK_PROPDESC_FLAG_CONFIGURABLE (1 << 2) /* E5 Section 8.6.1 */
4872#define DUK_PROPDESC_FLAG_ACCESSOR (1 << 3) /* accessor */
4873#define DUK_PROPDESC_FLAG_VIRTUAL (1 << 4) /* property is virtual: used in duk_propdesc, never stored
4874 * (used by e.g. buffer virtual properties)
4875 */
4876#define DUK_PROPDESC_FLAGS_MASK (DUK_PROPDESC_FLAG_WRITABLE | \
4877 DUK_PROPDESC_FLAG_ENUMERABLE | \
4878 DUK_PROPDESC_FLAG_CONFIGURABLE | \
4879 DUK_PROPDESC_FLAG_ACCESSOR)
4880
4881/* additional flags which are passed in the same flags argument as property
4882 * flags but are not stored in object properties.
4883 */
4884#define DUK_PROPDESC_FLAG_NO_OVERWRITE (1 << 4) /* internal define property: skip write silently if exists */
4885
4886/* convenience */
4887#define DUK_PROPDESC_FLAGS_NONE 0
4888#define DUK_PROPDESC_FLAGS_W (DUK_PROPDESC_FLAG_WRITABLE)
4889#define DUK_PROPDESC_FLAGS_E (DUK_PROPDESC_FLAG_ENUMERABLE)
4890#define DUK_PROPDESC_FLAGS_C (DUK_PROPDESC_FLAG_CONFIGURABLE)
4891#define DUK_PROPDESC_FLAGS_WE (DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_ENUMERABLE)
4892#define DUK_PROPDESC_FLAGS_WC (DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_CONFIGURABLE)
4893#define DUK_PROPDESC_FLAGS_EC (DUK_PROPDESC_FLAG_ENUMERABLE | DUK_PROPDESC_FLAG_CONFIGURABLE)
4894#define DUK_PROPDESC_FLAGS_WEC (DUK_PROPDESC_FLAG_WRITABLE | \
4895 DUK_PROPDESC_FLAG_ENUMERABLE | \
4896 DUK_PROPDESC_FLAG_CONFIGURABLE)
4897
11fdf7f2
TL
4898/* flags for duk_hobject_get_own_propdesc() and variants */
4899#define DUK_GETDESC_FLAG_PUSH_VALUE (1 << 0) /* push value to stack */
4900#define DUK_GETDESC_FLAG_IGNORE_PROTOLOOP (1 << 1) /* don't throw for prototype loop */
4901
7c673cae
FG
4902/*
4903 * Macro for object validity check
4904 *
4905 * Assert for currently guaranteed relations between flags, for instance.
4906 */
4907
4908#define DUK_ASSERT_HOBJECT_VALID(h) do { \
4909 DUK_ASSERT((h) != NULL); \
4910 DUK_ASSERT(!DUK_HOBJECT_IS_CALLABLE((h)) || \
4911 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FUNCTION); \
4912 DUK_ASSERT(!DUK_HOBJECT_IS_BUFFEROBJECT((h)) || \
4913 (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_BUFFER || \
4914 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAYBUFFER || \
4915 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_DATAVIEW || \
4916 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_INT8ARRAY || \
4917 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT8ARRAY || \
4918 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY || \
4919 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_INT16ARRAY || \
4920 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT16ARRAY || \
4921 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_INT32ARRAY || \
4922 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT32ARRAY || \
4923 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FLOAT32ARRAY || \
4924 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FLOAT64ARRAY)); \
4925 } while (0)
4926
4927/*
4928 * Macros to access the 'props' allocation.
4929 */
4930
4931#if defined(DUK_USE_HEAPPTR16)
4932#define DUK_HOBJECT_GET_PROPS(heap,h) \
4933 ((duk_uint8_t *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, ((duk_heaphdr *) (h))->h_extra16))
4934#define DUK_HOBJECT_SET_PROPS(heap,h,x) do { \
4935 ((duk_heaphdr *) (h))->h_extra16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (x)); \
4936 } while (0)
4937#else
4938#define DUK_HOBJECT_GET_PROPS(heap,h) \
4939 ((h)->props)
4940#define DUK_HOBJECT_SET_PROPS(heap,h,x) do { \
4941 (h)->props = (duk_uint8_t *) (x); \
4942 } while (0)
4943#endif
4944
4945#if defined(DUK_USE_HOBJECT_LAYOUT_1)
4946/* LAYOUT 1 */
4947#define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \
4948 ((duk_hstring **) (void *) ( \
4949 DUK_HOBJECT_GET_PROPS((heap), (h)) \
4950 ))
4951#define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \
4952 ((duk_propvalue *) (void *) ( \
4953 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
4954 DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_hstring *) \
4955 ))
4956#define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \
4957 ((duk_uint8_t *) (void *) ( \
4958 DUK_HOBJECT_GET_PROPS((heap), (h)) + DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue)) \
4959 ))
4960#define DUK_HOBJECT_A_GET_BASE(heap,h) \
4961 ((duk_tval *) (void *) ( \
4962 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
4963 DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) \
4964 ))
4965#define DUK_HOBJECT_H_GET_BASE(heap,h) \
4966 ((duk_uint32_t *) (void *) ( \
4967 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
4968 DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
4969 DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \
4970 ))
4971#define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \
4972 ( \
4973 (n_ent) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
4974 (n_arr) * sizeof(duk_tval) + \
4975 (n_hash) * sizeof(duk_uint32_t) \
4976 )
4977#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 { \
4978 (set_e_k) = (duk_hstring **) (void *) (p_base); \
4979 (set_e_pv) = (duk_propvalue *) (void *) ((set_e_k) + (n_ent)); \
4980 (set_e_f) = (duk_uint8_t *) (void *) ((set_e_pv) + (n_ent)); \
4981 (set_a) = (duk_tval *) (void *) ((set_e_f) + (n_ent)); \
4982 (set_h) = (duk_uint32_t *) (void *) ((set_a) + (n_arr)); \
4983 } while (0)
4984#elif defined(DUK_USE_HOBJECT_LAYOUT_2)
4985/* LAYOUT 2 */
4986#if (DUK_USE_ALIGN_BY == 4)
4987#define DUK_HOBJECT_E_FLAG_PADDING(e_sz) ((4 - (e_sz)) & 0x03)
4988#elif (DUK_USE_ALIGN_BY == 8)
4989#define DUK_HOBJECT_E_FLAG_PADDING(e_sz) ((8 - (e_sz)) & 0x07)
4990#elif (DUK_USE_ALIGN_BY == 1)
4991#define DUK_HOBJECT_E_FLAG_PADDING(e_sz) 0
4992#else
4993#error invalid DUK_USE_ALIGN_BY
4994#endif
4995#define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \
4996 ((duk_hstring **) (void *) ( \
4997 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
4998 DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) \
4999 ))
5000#define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \
5001 ((duk_propvalue *) (void *) ( \
5002 DUK_HOBJECT_GET_PROPS((heap), (h)) \
5003 ))
5004#define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \
5005 ((duk_uint8_t *) (void *) ( \
5006 DUK_HOBJECT_GET_PROPS((heap), (h)) + DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue)) \
5007 ))
5008#define DUK_HOBJECT_A_GET_BASE(heap,h) \
5009 ((duk_tval *) (void *) ( \
5010 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
5011 DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
5012 DUK_HOBJECT_E_FLAG_PADDING(DUK_HOBJECT_GET_ESIZE((h))) \
5013 ))
5014#define DUK_HOBJECT_H_GET_BASE(heap,h) \
5015 ((duk_uint32_t *) (void *) ( \
5016 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
5017 DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
5018 DUK_HOBJECT_E_FLAG_PADDING(DUK_HOBJECT_GET_ESIZE((h))) + \
5019 DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \
5020 ))
5021#define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \
5022 ( \
5023 (n_ent) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
5024 DUK_HOBJECT_E_FLAG_PADDING((n_ent)) + \
5025 (n_arr) * sizeof(duk_tval) + \
5026 (n_hash) * sizeof(duk_uint32_t) \
5027 )
5028#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 { \
5029 (set_e_pv) = (duk_propvalue *) (void *) (p_base); \
5030 (set_e_k) = (duk_hstring **) (void *) ((set_e_pv) + (n_ent)); \
5031 (set_e_f) = (duk_uint8_t *) (void *) ((set_e_k) + (n_ent)); \
5032 (set_a) = (duk_tval *) (void *) (((duk_uint8_t *) (set_e_f)) + \
5033 sizeof(duk_uint8_t) * (n_ent) + \
5034 DUK_HOBJECT_E_FLAG_PADDING((n_ent))); \
5035 (set_h) = (duk_uint32_t *) (void *) ((set_a) + (n_arr)); \
5036 } while (0)
5037#elif defined(DUK_USE_HOBJECT_LAYOUT_3)
5038/* LAYOUT 3 */
5039#define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \
5040 ((duk_hstring **) (void *) ( \
5041 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
5042 DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) + \
5043 DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \
5044 ))
5045#define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \
5046 ((duk_propvalue *) (void *) ( \
5047 DUK_HOBJECT_GET_PROPS((heap), (h)) \
5048 ))
5049#define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \
5050 ((duk_uint8_t *) (void *) ( \
5051 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
5052 DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_propvalue) + sizeof(duk_hstring *)) + \
5053 DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) + \
5054 DUK_HOBJECT_GET_HSIZE((h)) * sizeof(duk_uint32_t) \
5055 ))
5056#define DUK_HOBJECT_A_GET_BASE(heap,h) \
5057 ((duk_tval *) (void *) ( \
5058 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
5059 DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) \
5060 ))
5061#define DUK_HOBJECT_H_GET_BASE(heap,h) \
5062 ((duk_uint32_t *) (void *) ( \
5063 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
5064 DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_propvalue) + sizeof(duk_hstring *)) + \
5065 DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \
5066 ))
5067#define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \
5068 ( \
5069 (n_ent) * (sizeof(duk_propvalue) + sizeof(duk_hstring *) + sizeof(duk_uint8_t)) + \
5070 (n_arr) * sizeof(duk_tval) + \
5071 (n_hash) * sizeof(duk_uint32_t) \
5072 )
5073#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 { \
5074 (set_e_pv) = (duk_propvalue *) (void *) (p_base); \
5075 (set_a) = (duk_tval *) (void *) ((set_e_pv) + (n_ent)); \
5076 (set_e_k) = (duk_hstring **) (void *) ((set_a) + (n_arr)); \
5077 (set_h) = (duk_uint32_t *) (void *) ((set_e_k) + (n_ent)); \
5078 (set_e_f) = (duk_uint8_t *) (void *) ((set_h) + (n_hash)); \
5079 } while (0)
5080#else
5081#error invalid hobject layout defines
5082#endif /* hobject property layout */
5083
11fdf7f2 5084#define DUK_HOBJECT_P_ALLOC_SIZE(h) \
7c673cae
FG
5085 DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE((h)), DUK_HOBJECT_GET_ASIZE((h)), DUK_HOBJECT_GET_HSIZE((h)))
5086
5087#define DUK_HOBJECT_E_GET_KEY(heap,h,i) (DUK_HOBJECT_E_GET_KEY_BASE((heap), (h))[(i)])
5088#define DUK_HOBJECT_E_GET_KEY_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_KEY_BASE((heap), (h))[(i)])
5089#define DUK_HOBJECT_E_GET_VALUE(heap,h,i) (DUK_HOBJECT_E_GET_VALUE_BASE((heap), (h))[(i)])
5090#define DUK_HOBJECT_E_GET_VALUE_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE_BASE((heap), (h))[(i)])
5091#define DUK_HOBJECT_E_GET_VALUE_TVAL(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v)
5092#define DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v)
5093#define DUK_HOBJECT_E_GET_VALUE_GETTER(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get)
5094#define DUK_HOBJECT_E_GET_VALUE_GETTER_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get)
5095#define DUK_HOBJECT_E_GET_VALUE_SETTER(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set)
5096#define DUK_HOBJECT_E_GET_VALUE_SETTER_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set)
5097#define DUK_HOBJECT_E_GET_FLAGS(heap,h,i) (DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)])
5098#define DUK_HOBJECT_E_GET_FLAGS_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)])
5099#define DUK_HOBJECT_A_GET_VALUE(heap,h,i) (DUK_HOBJECT_A_GET_BASE((heap), (h))[(i)])
5100#define DUK_HOBJECT_A_GET_VALUE_PTR(heap,h,i) (&DUK_HOBJECT_A_GET_BASE((heap), (h))[(i)])
5101#define DUK_HOBJECT_H_GET_INDEX(heap,h,i) (DUK_HOBJECT_H_GET_BASE((heap), (h))[(i)])
5102#define DUK_HOBJECT_H_GET_INDEX_PTR(heap,h,i) (&DUK_HOBJECT_H_GET_BASE((heap), (h))[(i)])
5103
5104#define DUK_HOBJECT_E_SET_KEY(heap,h,i,k) do { \
5105 DUK_HOBJECT_E_GET_KEY((heap), (h), (i)) = (k); \
5106 } while (0)
5107#define DUK_HOBJECT_E_SET_VALUE(heap,h,i,v) do { \
5108 DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)) = (v); \
5109 } while (0)
5110#define DUK_HOBJECT_E_SET_VALUE_TVAL(heap,h,i,v) do { \
5111 DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v = (v); \
5112 } while (0)
5113#define DUK_HOBJECT_E_SET_VALUE_GETTER(heap,h,i,v) do { \
5114 DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get = (v); \
5115 } while (0)
5116#define DUK_HOBJECT_E_SET_VALUE_SETTER(heap,h,i,v) do { \
5117 DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set = (v); \
5118 } while (0)
5119#define DUK_HOBJECT_E_SET_FLAGS(heap,h,i,f) do { \
11fdf7f2 5120 DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) = (duk_uint8_t) (f); \
7c673cae
FG
5121 } while (0)
5122#define DUK_HOBJECT_A_SET_VALUE(heap,h,i,v) do { \
5123 DUK_HOBJECT_A_GET_VALUE((heap), (h), (i)) = (v); \
5124 } while (0)
5125#define DUK_HOBJECT_A_SET_VALUE_TVAL(heap,h,i,v) \
5126 DUK_HOBJECT_A_SET_VALUE((heap), (h), (i), (v)) /* alias for above */
5127#define DUK_HOBJECT_H_SET_INDEX(heap,h,i,v) do { \
5128 DUK_HOBJECT_H_GET_INDEX((heap), (h), (i)) = (v); \
5129 } while (0)
5130
5131#define DUK_HOBJECT_E_SET_FLAG_BITS(heap,h,i,mask) do { \
5132 DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)] |= (mask); \
5133 } while (0)
5134
5135#define DUK_HOBJECT_E_CLEAR_FLAG_BITS(heap,h,i,mask) do { \
5136 DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)] &= ~(mask); \
5137 } while (0)
5138
5139#define DUK_HOBJECT_E_SLOT_IS_WRITABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_WRITABLE) != 0)
5140#define DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_ENUMERABLE) != 0)
5141#define DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_CONFIGURABLE) != 0)
5142#define DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_ACCESSOR) != 0)
5143
5144#define DUK_HOBJECT_E_SLOT_SET_WRITABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_WRITABLE)
5145#define DUK_HOBJECT_E_SLOT_SET_ENUMERABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ENUMERABLE)
5146#define DUK_HOBJECT_E_SLOT_SET_CONFIGURABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_CONFIGURABLE)
5147#define DUK_HOBJECT_E_SLOT_SET_ACCESSOR(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ACCESSOR)
5148
5149#define DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_WRITABLE)
5150#define DUK_HOBJECT_E_SLOT_CLEAR_ENUMERABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ENUMERABLE)
5151#define DUK_HOBJECT_E_SLOT_CLEAR_CONFIGURABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_CONFIGURABLE)
5152#define DUK_HOBJECT_E_SLOT_CLEAR_ACCESSOR(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ACCESSOR)
5153
5154#define DUK_PROPDESC_IS_WRITABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_WRITABLE) != 0)
5155#define DUK_PROPDESC_IS_ENUMERABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_ENUMERABLE) != 0)
5156#define DUK_PROPDESC_IS_CONFIGURABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_CONFIGURABLE) != 0)
5157#define DUK_PROPDESC_IS_ACCESSOR(p) (((p)->flags & DUK_PROPDESC_FLAG_ACCESSOR) != 0)
5158
5159#define DUK_HOBJECT_HASHIDX_UNUSED 0xffffffffUL
5160#define DUK_HOBJECT_HASHIDX_DELETED 0xfffffffeUL
5161
5162/*
5163 * Macros for accessing size fields
5164 */
5165
5166#if defined(DUK_USE_OBJSIZES16)
5167#define DUK_HOBJECT_GET_ESIZE(h) ((h)->e_size16)
5168#define DUK_HOBJECT_SET_ESIZE(h,v) do { (h)->e_size16 = (v); } while (0)
5169#define DUK_HOBJECT_GET_ENEXT(h) ((h)->e_next16)
5170#define DUK_HOBJECT_SET_ENEXT(h,v) do { (h)->e_next16 = (v); } while (0)
5171#define DUK_HOBJECT_POSTINC_ENEXT(h) ((h)->e_next16++)
5172#define DUK_HOBJECT_GET_ASIZE(h) ((h)->a_size16)
5173#define DUK_HOBJECT_SET_ASIZE(h,v) do { (h)->a_size16 = (v); } while (0)
5174#if defined(DUK_USE_HOBJECT_HASH_PART)
5175#define DUK_HOBJECT_GET_HSIZE(h) ((h)->h_size16)
5176#define DUK_HOBJECT_SET_HSIZE(h,v) do { (h)->h_size16 = (v); } while (0)
5177#else
5178#define DUK_HOBJECT_GET_HSIZE(h) 0
5179#define DUK_HOBJECT_SET_HSIZE(h,v) do { DUK_ASSERT((v) == 0); } while (0)
5180#endif
5181#else
5182#define DUK_HOBJECT_GET_ESIZE(h) ((h)->e_size)
5183#define DUK_HOBJECT_SET_ESIZE(h,v) do { (h)->e_size = (v); } while (0)
5184#define DUK_HOBJECT_GET_ENEXT(h) ((h)->e_next)
5185#define DUK_HOBJECT_SET_ENEXT(h,v) do { (h)->e_next = (v); } while (0)
5186#define DUK_HOBJECT_POSTINC_ENEXT(h) ((h)->e_next++)
5187#define DUK_HOBJECT_GET_ASIZE(h) ((h)->a_size)
5188#define DUK_HOBJECT_SET_ASIZE(h,v) do { (h)->a_size = (v); } while (0)
5189#if defined(DUK_USE_HOBJECT_HASH_PART)
5190#define DUK_HOBJECT_GET_HSIZE(h) ((h)->h_size)
5191#define DUK_HOBJECT_SET_HSIZE(h,v) do { (h)->h_size = (v); } while (0)
5192#else
5193#define DUK_HOBJECT_GET_HSIZE(h) 0
5194#define DUK_HOBJECT_SET_HSIZE(h,v) do { DUK_ASSERT((v) == 0); } while (0)
5195#endif
5196#endif
5197
5198/*
5199 * Misc
5200 */
5201
5202/* Maximum prototype traversal depth. Sanity limit which handles e.g.
5203 * prototype loops (even complex ones like 1->2->3->4->2->3->4->2->3->4).
5204 */
5205#define DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY 10000L
5206
5207/* Maximum traversal depth for "bound function" chains. */
5208#define DUK_HOBJECT_BOUND_CHAIN_SANITY 10000L
5209
5210/*
5211 * Ecmascript [[Class]]
5212 */
5213
5214/* range check not necessary because all 4-bit values are mapped */
5215#define DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(n) duk_class_number_to_stridx[(n)]
5216
5217#define DUK_HOBJECT_GET_CLASS_STRING(heap,h) \
5218 DUK_HEAP_GET_STRING( \
5219 (heap), \
5220 DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(DUK_HOBJECT_GET_CLASS_NUMBER((h))) \
5221 )
5222
5223/*
5224 * Macros for property handling
5225 */
5226
5227#if defined(DUK_USE_HEAPPTR16)
5228#define DUK_HOBJECT_GET_PROTOTYPE(heap,h) \
5229 ((duk_hobject *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->prototype16))
5230#define DUK_HOBJECT_SET_PROTOTYPE(heap,h,x) do { \
5231 (h)->prototype16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (x)); \
5232 } while (0)
5233#else
5234#define DUK_HOBJECT_GET_PROTOTYPE(heap,h) \
5235 ((h)->prototype)
5236#define DUK_HOBJECT_SET_PROTOTYPE(heap,h,x) do { \
5237 (h)->prototype = (x); \
5238 } while (0)
5239#endif
5240
5241/* note: this updates refcounts */
11fdf7f2 5242#define DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr,h,p) duk_hobject_set_prototype_updref((thr), (h), (p))
7c673cae
FG
5243
5244/*
5245 * Resizing and hash behavior
5246 */
5247
5248/* Sanity limit on max number of properties (allocated, not necessarily used).
5249 * This is somewhat arbitrary, but if we're close to 2**32 properties some
5250 * algorithms will fail (e.g. hash size selection, next prime selection).
5251 * Also, we use negative array/entry table indices to indicate 'not found',
5252 * so anything above 0x80000000 will cause trouble now.
5253 */
5254#if defined(DUK_USE_OBJSIZES16)
5255#define DUK_HOBJECT_MAX_PROPERTIES 0x0000ffffUL
5256#else
5257#define DUK_HOBJECT_MAX_PROPERTIES 0x7fffffffUL /* 2**31-1 ~= 2G properties */
5258#endif
5259
5260/* higher value conserves memory; also note that linear scan is cache friendly */
5261#define DUK_HOBJECT_E_USE_HASH_LIMIT 32
5262
5263/* hash size relative to entries size: for value X, approx. hash_prime(e_size + e_size / X) */
5264#define DUK_HOBJECT_H_SIZE_DIVISOR 4 /* hash size approx. 1.25 times entries size */
5265
5266/* if new_size < L * old_size, resize without abandon check; L = 3-bit fixed point, e.g. 9 -> 9/8 = 112.5% */
5267#define DUK_HOBJECT_A_FAST_RESIZE_LIMIT 9 /* 112.5%, i.e. new size less than 12.5% higher -> fast resize */
5268
5269/* if density < L, abandon array part, L = 3-bit fixed point, e.g. 2 -> 2/8 = 25% */
5270/* limit is quite low: one array entry is 8 bytes, one normal entry is 4+1+8+4 = 17 bytes (with hash entry) */
5271#define DUK_HOBJECT_A_ABANDON_LIMIT 2 /* 25%, i.e. less than 25% used -> abandon */
5272
5273/* internal align target for props allocation, must be 2*n for some n */
5274#if (DUK_USE_ALIGN_BY == 4)
5275#define DUK_HOBJECT_ALIGN_TARGET 4
5276#elif (DUK_USE_ALIGN_BY == 8)
5277#define DUK_HOBJECT_ALIGN_TARGET 8
5278#elif (DUK_USE_ALIGN_BY == 1)
5279#define DUK_HOBJECT_ALIGN_TARGET 1
5280#else
5281#error invalid DUK_USE_ALIGN_BY
5282#endif
5283
5284/* controls for minimum entry part growth */
5285#define DUK_HOBJECT_E_MIN_GROW_ADD 16
5286#define DUK_HOBJECT_E_MIN_GROW_DIVISOR 8 /* 2^3 -> 1/8 = 12.5% min growth */
5287
5288/* controls for minimum array part growth */
5289#define DUK_HOBJECT_A_MIN_GROW_ADD 16
5290#define DUK_HOBJECT_A_MIN_GROW_DIVISOR 8 /* 2^3 -> 1/8 = 12.5% min growth */
5291
5292/* probe sequence */
5293#define DUK_HOBJECT_HASH_INITIAL(hash,h_size) ((hash) % (h_size))
5294#define DUK_HOBJECT_HASH_PROBE_STEP(hash) DUK_UTIL_GET_HASH_PROBE_STEP((hash))
5295
5296/*
5297 * PC-to-line constants
5298 */
5299
5300#define DUK_PC2LINE_SKIP 64
5301
5302/* maximum length for a SKIP-1 diffstream: 35 bits per entry, rounded up to bytes */
5303#define DUK_PC2LINE_MAX_DIFF_LENGTH (((DUK_PC2LINE_SKIP - 1) * 35 + 7) / 8)
5304
5305/*
5306 * Struct defs
5307 */
5308
5309struct duk_propaccessor {
5310 duk_hobject *get;
5311 duk_hobject *set;
5312};
5313
5314union duk_propvalue {
5315 /* The get/set pointers could be 16-bit pointer compressed but it
5316 * would make no difference on 32-bit platforms because duk_tval is
5317 * 8 bytes or more anyway.
5318 */
5319 duk_tval v;
5320 duk_propaccessor a;
5321};
5322
5323struct duk_propdesc {
5324 /* read-only values 'lifted' for ease of use */
5325 duk_small_int_t flags;
5326 duk_hobject *get;
5327 duk_hobject *set;
5328
5329 /* for updating (all are set to < 0 for virtual properties) */
5330 duk_int_t e_idx; /* prop index in 'entry part', < 0 if not there */
5331 duk_int_t h_idx; /* prop index in 'hash part', < 0 if not there */
5332 duk_int_t a_idx; /* prop index in 'array part', < 0 if not there */
5333};
5334
5335struct duk_hobject {
5336 duk_heaphdr hdr;
5337
5338 /*
5339 * 'props' contains {key,value,flags} entries, optional array entries, and
5340 * an optional hash lookup table for non-array entries in a single 'sliced'
5341 * allocation. There are several layout options, which differ slightly in
5342 * generated code size/speed and alignment/padding; duk_features.h selects
5343 * the layout used.
5344 *
5345 * Layout 1 (DUK_USE_HOBJECT_LAYOUT_1):
5346 *
5347 * e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable)
5348 * e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable)
5349 * e_size * sizeof(duk_uint8_t) bytes of entry flags (e_next gc reachable)
5350 * a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable)
5351 * h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size),
5352 * 0xffffffffUL = unused, 0xfffffffeUL = deleted
5353 *
5354 * Layout 2 (DUK_USE_HOBJECT_LAYOUT_2):
5355 *
5356 * e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable)
5357 * e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable)
5358 * e_size * sizeof(duk_uint8_t) + pad bytes of entry flags (e_next gc reachable)
5359 * a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable)
5360 * h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size),
5361 * 0xffffffffUL = unused, 0xfffffffeUL = deleted
5362 *
5363 * Layout 3 (DUK_USE_HOBJECT_LAYOUT_3):
5364 *
5365 * e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable)
5366 * a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable)
5367 * e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable)
5368 * h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size),
5369 * 0xffffffffUL = unused, 0xfffffffeUL = deleted
5370 * e_size * sizeof(duk_uint8_t) bytes of entry flags (e_next gc reachable)
5371 *
5372 * In layout 1, the 'e_next' count is rounded to 4 or 8 on platforms
5373 * requiring 4 or 8 byte alignment. This ensures proper alignment
5374 * for the entries, at the cost of memory footprint. However, it's
5375 * probably preferable to use another layout on such platforms instead.
5376 *
5377 * In layout 2, the key and value parts are swapped to avoid padding
5378 * the key array on platforms requiring alignment by 8. The flags part
5379 * is padded to get alignment for array entries. The 'e_next' count does
5380 * not need to be rounded as in layout 1.
5381 *
5382 * In layout 3, entry values and array values are always aligned properly,
5383 * and assuming pointers are at most 8 bytes, so are the entry keys. Hash
5384 * indices will be properly aligned (assuming pointers are at least 4 bytes).
5385 * Finally, flags don't need additional alignment. This layout provides
5386 * compact allocations without padding (even on platforms with alignment
5387 * requirements) at the cost of a bit slower lookups.
5388 *
5389 * Objects with few keys don't have a hash index; keys are looked up linearly,
5390 * which is cache efficient because the keys are consecutive. Larger objects
5391 * have a hash index part which contains integer indexes to the entries part.
5392 *
5393 * A single allocation reduces memory allocation overhead but requires more
5394 * work when any part needs to be resized. A sliced allocation for entries
5395 * makes linear key matching faster on most platforms (more locality) and
5396 * skimps on flags size (which would be followed by 3 bytes of padding in
5397 * most architectures if entries were placed in a struct).
5398 *
5399 * 'props' also contains internal properties distinguished with a non-BMP
5400 * prefix. Often used properties should be placed early in 'props' whenever
5401 * possible to make accessing them as fast a possible.
5402 */
5403
5404#if defined(DUK_USE_HEAPPTR16)
5405 /* Located in duk_heaphdr h_extra16. Subclasses of duk_hobject (like
5406 * duk_hcompiledfunction) are not free to use h_extra16 for this reason.
5407 */
5408#else
5409 duk_uint8_t *props;
5410#endif
5411
5412 /* prototype: the only internal property lifted outside 'e' as it is so central */
5413#if defined(DUK_USE_HEAPPTR16)
5414 duk_uint16_t prototype16;
5415#else
5416 duk_hobject *prototype;
5417#endif
5418
5419#if defined(DUK_USE_OBJSIZES16)
5420 duk_uint16_t e_size16;
5421 duk_uint16_t e_next16;
5422 duk_uint16_t a_size16;
5423#if defined(DUK_USE_HOBJECT_HASH_PART)
5424 duk_uint16_t h_size16;
5425#endif
5426#else
5427 duk_uint32_t e_size; /* entry part size */
5428 duk_uint32_t e_next; /* index for next new key ([0,e_next[ are gc reachable) */
5429 duk_uint32_t a_size; /* array part size (entirely gc reachable) */
5430#if defined(DUK_USE_HOBJECT_HASH_PART)
5431 duk_uint32_t h_size; /* hash part size or 0 if unused */
5432#endif
5433#endif
5434};
5435
5436/*
5437 * Exposed data
5438 */
5439
5440#if !defined(DUK_SINGLE_FILE)
5441DUK_INTERNAL_DECL duk_uint8_t duk_class_number_to_stridx[32];
5442#endif /* !DUK_SINGLE_FILE */
5443
5444/*
5445 * Prototypes
5446 */
5447
5448/* alloc and init */
5449DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc(duk_heap *heap, duk_uint_t hobject_flags);
5450#if 0 /* unused */
5451DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc_checked(duk_hthread *thr, duk_uint_t hobject_flags);
5452#endif
5453DUK_INTERNAL_DECL duk_hcompiledfunction *duk_hcompiledfunction_alloc(duk_heap *heap, duk_uint_t hobject_flags);
5454DUK_INTERNAL_DECL duk_hnativefunction *duk_hnativefunction_alloc(duk_heap *heap, duk_uint_t hobject_flags);
5455DUK_INTERNAL duk_hbufferobject *duk_hbufferobject_alloc(duk_heap *heap, duk_uint_t hobject_flags);
5456DUK_INTERNAL_DECL duk_hthread *duk_hthread_alloc(duk_heap *heap, duk_uint_t hobject_flags);
5457
5458/* low-level property functions */
5459DUK_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);
5460DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_hstring *key);
5461DUK_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);
5462DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_array_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_uarridx_t i);
11fdf7f2 5463DUK_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);
7c673cae
FG
5464
5465/* XXX: when optimizing for guaranteed property slots, use a guaranteed
5466 * slot for internal value; this call can then access it directly.
5467 */
5468#define duk_hobject_get_internal_value_tval_ptr(heap,obj) \
5469 duk_hobject_find_existing_entry_tval_ptr((heap), (obj), DUK_HEAP_STRING_INT_VALUE((heap)))
5470
5471/* core property functions */
5472DUK_INTERNAL_DECL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key);
5473DUK_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);
5474DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_bool_t throw_flag);
5475DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key);
5476
5477/* internal property functions */
5478#define DUK_DELPROP_FLAG_THROW (1 << 0)
5479#define DUK_DELPROP_FLAG_FORCE (1 << 1)
5480DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags);
5481DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key);
5482DUK_INTERNAL_DECL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags);
5483DUK_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);
5484DUK_INTERNAL_DECL void duk_hobject_define_accessor_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_hobject *getter, duk_hobject *setter, duk_small_uint_t propflags);
5485DUK_INTERNAL_DECL void duk_hobject_set_length(duk_hthread *thr, duk_hobject *obj, duk_uint32_t length); /* XXX: duk_uarridx_t? */
5486DUK_INTERNAL_DECL void duk_hobject_set_length_zero(duk_hthread *thr, duk_hobject *obj);
5487DUK_INTERNAL_DECL duk_uint32_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj); /* XXX: duk_uarridx_t? */
5488
5489/* helpers for defineProperty() and defineProperties() */
5490DUK_INTERNAL_DECL
5491void duk_hobject_prepare_property_descriptor(duk_context *ctx,
5492 duk_idx_t idx_in,
5493 duk_uint_t *out_defprop_flags,
5494 duk_idx_t *out_idx_value,
5495 duk_hobject **out_getter,
5496 duk_hobject **out_setter);
5497DUK_INTERNAL_DECL
5498void duk_hobject_define_property_helper(duk_context *ctx,
5499 duk_uint_t defprop_flags,
5500 duk_hobject *obj,
5501 duk_hstring *key,
5502 duk_idx_t idx_value,
5503 duk_hobject *get,
5504 duk_hobject *set);
5505
5506/* Object built-in methods */
5507DUK_INTERNAL_DECL duk_ret_t duk_hobject_object_get_own_property_descriptor(duk_context *ctx);
5508DUK_INTERNAL_DECL void duk_hobject_object_seal_freeze_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_freeze);
5509DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_is_sealed_frozen_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_frozen);
5510DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_ownprop_helper(duk_context *ctx, duk_small_uint_t required_desc_flags);
5511
5512/* internal properties */
5513DUK_INTERNAL_DECL duk_bool_t duk_hobject_get_internal_value(duk_heap *heap, duk_hobject *obj, duk_tval *tv);
5514DUK_INTERNAL_DECL duk_hstring *duk_hobject_get_internal_value_string(duk_heap *heap, duk_hobject *obj);
5515
5516/* hobject management functions */
5517DUK_INTERNAL_DECL void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj);
5518
5519/* ES6 proxy */
5520#if defined(DUK_USE_ES6_PROXY)
5521DUK_INTERNAL_DECL duk_bool_t duk_hobject_proxy_check(duk_hthread *thr, duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler);
5522DUK_INTERNAL_DECL duk_hobject *duk_hobject_resolve_proxy_target(duk_hthread *thr, duk_hobject *obj);
5523#endif
5524
5525/* enumeration */
5526DUK_INTERNAL_DECL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint_t enum_flags);
5527DUK_INTERNAL_DECL duk_ret_t duk_hobject_get_enumerated_keys(duk_context *ctx, duk_small_uint_t enum_flags);
5528DUK_INTERNAL_DECL duk_bool_t duk_hobject_enumerator_next(duk_context *ctx, duk_bool_t get_value);
5529
5530/* macros */
11fdf7f2 5531DUK_INTERNAL_DECL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p);
7c673cae
FG
5532
5533/* finalization */
5534DUK_INTERNAL_DECL void duk_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj);
5535
5536/* pc2line */
5537#if defined(DUK_USE_PC2LINE)
5538DUK_INTERNAL_DECL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr *instrs, duk_uint_fast32_t length);
5539DUK_INTERNAL_DECL duk_uint_fast32_t duk_hobject_pc2line_query(duk_context *ctx, duk_idx_t idx_func, duk_uint_fast32_t pc);
5540#endif
5541
5542/* misc */
5543DUK_INTERNAL_DECL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *thr, duk_hobject *h, duk_hobject *p, duk_bool_t ignore_loop);
5544
5545#endif /* DUK_HOBJECT_H_INCLUDED */
7c673cae
FG
5546/*
5547 * Heap compiled function (Ecmascript function) representation.
5548 *
5549 * There is a single data buffer containing the Ecmascript function's
5550 * bytecode, constants, and inner functions.
5551 */
5552
5553#ifndef DUK_HCOMPILEDFUNCTION_H_INCLUDED
5554#define DUK_HCOMPILEDFUNCTION_H_INCLUDED
5555
5556/*
5557 * Field accessor macros
5558 */
5559
5560/* XXX: casts could be improved, especially for GET/SET DATA */
5561
5562#if defined(DUK_USE_HEAPPTR16)
5563#define DUK_HCOMPILEDFUNCTION_GET_DATA(heap,h) \
5564 ((duk_hbuffer_fixed *) (void *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->data16))
5565#define DUK_HCOMPILEDFUNCTION_SET_DATA(heap,h,v) do { \
5566 (h)->data16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
5567 } while (0)
5568#define DUK_HCOMPILEDFUNCTION_GET_FUNCS(heap,h) \
5569 ((duk_hobject **) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->funcs16)))
5570#define DUK_HCOMPILEDFUNCTION_SET_FUNCS(heap,h,v) do { \
5571 (h)->funcs16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
5572 } while (0)
5573#define DUK_HCOMPILEDFUNCTION_GET_BYTECODE(heap,h) \
5574 ((duk_instr_t *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->bytecode16)))
5575#define DUK_HCOMPILEDFUNCTION_SET_BYTECODE(heap,h,v) do { \
5576 (h)->bytecode16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
5577 } while (0)
5578#else
5579#define DUK_HCOMPILEDFUNCTION_GET_DATA(heap,h) \
5580 ((duk_hbuffer_fixed *) (void *) (h)->data)
5581#define DUK_HCOMPILEDFUNCTION_SET_DATA(heap,h,v) do { \
5582 (h)->data = (duk_hbuffer *) (v); \
5583 } while (0)
5584#define DUK_HCOMPILEDFUNCTION_GET_FUNCS(heap,h) \
5585 ((h)->funcs)
5586#define DUK_HCOMPILEDFUNCTION_SET_FUNCS(heap,h,v) do { \
5587 (h)->funcs = (v); \
5588 } while (0)
5589#define DUK_HCOMPILEDFUNCTION_GET_BYTECODE(heap,h) \
5590 ((h)->bytecode)
5591#define DUK_HCOMPILEDFUNCTION_SET_BYTECODE(heap,h,v) do { \
5592 (h)->bytecode = (v); \
5593 } while (0)
5594#endif
5595
5596/*
5597 * Accessor macros for function specific data areas
5598 */
5599
5600/* Note: assumes 'data' is always a fixed buffer */
5601#define DUK_HCOMPILEDFUNCTION_GET_BUFFER_BASE(heap,h) \
5602 DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPILEDFUNCTION_GET_DATA((heap), (h)))
5603
5604#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(heap,h) \
5605 ((duk_tval *) (void *) DUK_HCOMPILEDFUNCTION_GET_BUFFER_BASE((heap), (h)))
5606
5607#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(heap,h) \
5608 DUK_HCOMPILEDFUNCTION_GET_FUNCS((heap), (h))
5609
5610#define DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(heap,h) \
5611 DUK_HCOMPILEDFUNCTION_GET_BYTECODE((heap), (h))
5612
5613#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(heap,h) \
5614 ((duk_tval *) (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS((heap), (h)))
5615
5616#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(heap,h) \
5617 ((duk_hobject **) (void *) DUK_HCOMPILEDFUNCTION_GET_BYTECODE((heap), (h)))
5618
5619/* XXX: double evaluation of DUK_HCOMPILEDFUNCTION_GET_DATA() */
5620#define DUK_HCOMPILEDFUNCTION_GET_CODE_END(heap,h) \
5621 ((duk_instr_t *) (void *) (DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPILEDFUNCTION_GET_DATA((heap), (h))) + \
5622 DUK_HBUFFER_GET_SIZE((duk_hbuffer *) DUK_HCOMPILEDFUNCTION_GET_DATA((heap), h))))
5623
5624#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE(heap,h) \
5625 ( \
5626 (duk_size_t) \
5627 ( \
5628 ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_END((heap), (h))) - \
5629 ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE((heap), (h))) \
5630 ) \
5631 )
5632
5633#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE(heap,h) \
5634 ( \
5635 (duk_size_t) \
5636 ( \
5637 ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END((heap), (h))) - \
5638 ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE((heap), (h))) \
5639 ) \
5640 )
5641
5642#define DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE(heap,h) \
5643 ( \
5644 (duk_size_t) \
5645 ( \
5646 ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CODE_END((heap),(h))) - \
5647 ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE((heap),(h))) \
5648 ) \
5649 )
5650
5651#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(heap,h) \
5652 ((duk_size_t) (DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE((heap), (h)) / sizeof(duk_tval)))
5653
5654#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(heap,h) \
5655 ((duk_size_t) (DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE((heap), (h)) / sizeof(duk_hobject *)))
5656
5657#define DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(heap,h) \
5658 ((duk_size_t) (DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE((heap), (h)) / sizeof(duk_instr_t)))
5659
5660
5661/*
5662 * Main struct
5663 */
5664
5665struct duk_hcompiledfunction {
5666 /* shared object part */
5667 duk_hobject obj;
5668
5669 /*
5670 * Pointers to function data area for faster access. Function
5671 * data is a buffer shared between all closures of the same
5672 * "template" function. The data buffer is always fixed (non-
5673 * dynamic, hence stable), with a layout as follows:
5674 *
5675 * constants (duk_tval)
5676 * inner functions (duk_hobject *)
5677 * bytecode (duk_instr_t)
5678 *
5679 * Note: bytecode end address can be computed from 'data' buffer
5680 * size. It is not strictly necessary functionally, assuming
5681 * bytecode never jumps outside its allocated area. However,
5682 * it's a safety/robustness feature for avoiding the chance of
5683 * executing random data as bytecode due to a compiler error.
5684 *
5685 * Note: values in the data buffer must be incref'd (they will
5686 * be decref'd on release) for every compiledfunction referring
5687 * to the 'data' element.
5688 */
5689
5690 /* Data area, fixed allocation, stable data ptrs. */
5691#if defined(DUK_USE_HEAPPTR16)
5692 duk_uint16_t data16;
5693#else
5694 duk_hbuffer *data;
5695#endif
5696
5697 /* No need for constants pointer (= same as data).
5698 *
5699 * When using 16-bit packing alignment to 4 is nice. 'funcs' will be
5700 * 4-byte aligned because 'constants' are duk_tvals. For now the
5701 * inner function pointers are not compressed, so that 'bytecode' will
5702 * also be 4-byte aligned.
5703 */
5704#if defined(DUK_USE_HEAPPTR16)
5705 duk_uint16_t funcs16;
5706 duk_uint16_t bytecode16;
5707#else
5708 duk_hobject **funcs;
5709 duk_instr_t *bytecode;
5710#endif
5711
5712 /*
5713 * 'nregs' registers are allocated on function entry, at most 'nargs'
5714 * are initialized to arguments, and the rest to undefined. Arguments
5715 * above 'nregs' are not mapped to registers. All registers in the
5716 * active stack range must be initialized because they are GC reachable.
5717 * 'nargs' is needed so that if the function is given more than 'nargs'
5718 * arguments, the additional arguments do not 'clobber' registers
5719 * beyond 'nregs' which must be consistently initialized to undefined.
5720 *
5721 * Usually there is no need to know which registers are mapped to
5722 * local variables. Registers may be allocated to variable in any
5723 * way (even including gaps). However, a register-variable mapping
5724 * must be the same for the duration of the function execution and
5725 * the register cannot be used for anything else.
5726 *
5727 * When looking up variables by name, the '_Varmap' map is used.
5728 * When an activation closes, registers mapped to arguments are
5729 * copied into the environment record based on the same map. The
5730 * reverse map (from register to variable) is not currently needed
5731 * at run time, except for debugging, so it is not maintained.
5732 */
5733
5734 duk_uint16_t nregs; /* regs to allocate */
5735 duk_uint16_t nargs; /* number of arguments allocated to regs */
5736
5737 /*
5738 * Additional control information is placed into the object itself
5739 * as internal properties to avoid unnecessary fields for the
5740 * majority of functions. The compiler tries to omit internal
5741 * control fields when possible.
5742 *
5743 * Function templates:
5744 *
5745 * {
5746 * name: "func", // declaration, named function expressions
5747 * fileName: <debug info for creating nice errors>
5748 * _Varmap: { "arg1": 0, "arg2": 1, "varname": 2 },
5749 * _Formals: [ "arg1", "arg2" ],
5750 * _Source: "function func(arg1, arg2) { ... }",
5751 * _Pc2line: <debug info for pc-to-line mapping>,
5752 * }
5753 *
5754 * Function instances:
5755 *
5756 * {
5757 * length: 2,
5758 * prototype: { constructor: <func> },
5759 * caller: <thrower>,
5760 * arguments: <thrower>,
5761 * name: "func", // declaration, named function expressions
5762 * fileName: <debug info for creating nice errors>
5763 * _Varmap: { "arg1": 0, "arg2": 1, "varname": 2 },
5764 * _Formals: [ "arg1", "arg2" ],
5765 * _Source: "function func(arg1, arg2) { ... }",
5766 * _Pc2line: <debug info for pc-to-line mapping>,
5767 * _Varenv: <variable environment of closure>,
5768 * _Lexenv: <lexical environment of closure (if differs from _Varenv)>
5769 * }
5770 *
5771 * More detailed description of these properties can be found
5772 * in the documentation.
5773 */
5774
5775#if defined(DUK_USE_DEBUGGER_SUPPORT)
5776 /* Line number range for function. Needed during debugging to
5777 * determine active breakpoints.
5778 */
5779 duk_uint32_t start_line;
5780 duk_uint32_t end_line;
5781#endif
5782};
5783
5784#endif /* DUK_HCOMPILEDFUNCTION_H_INCLUDED */
7c673cae
FG
5785/*
5786 * Heap native function representation.
5787 */
5788
5789#ifndef DUK_HNATIVEFUNCTION_H_INCLUDED
5790#define DUK_HNATIVEFUNCTION_H_INCLUDED
5791
5792#define DUK_HNATIVEFUNCTION_NARGS_VARARGS ((duk_int16_t) -1)
5793#define DUK_HNATIVEFUNCTION_NARGS_MAX ((duk_int16_t) 0x7fff)
5794
5795struct duk_hnativefunction {
5796 /* shared object part */
5797 duk_hobject obj;
5798
5799 duk_c_function func;
5800 duk_int16_t nargs;
5801 duk_int16_t magic;
5802
5803 /* The 'magic' field allows an opaque 16-bit field to be accessed by the
5804 * Duktape/C function. This allows, for instance, the same native function
5805 * to be used for a set of very similar functions, with the 'magic' field
5806 * providing the necessary non-argument flags / values to guide the behavior
5807 * of the native function. The value is signed on purpose: it is easier to
5808 * convert a signed value to unsigned (simply AND with 0xffff) than vice
5809 * versa.
5810 *
5811 * Note: cannot place nargs/magic into the heaphdr flags, because
5812 * duk_hobject takes almost all flags already (and needs the spare).
5813 */
5814};
5815
5816#endif /* DUK_HNATIVEFUNCTION_H_INCLUDED */
7c673cae
FG
5817/*
5818 * Heap Buffer object representation. Used for all Buffer variants.
5819 */
5820
5821#ifndef DUK_HBUFFEROBJECT_H_INCLUDED
5822#define DUK_HBUFFEROBJECT_H_INCLUDED
5823
5824/* All element accessors are host endian now (driven by TypedArray spec). */
5825#define DUK_HBUFFEROBJECT_ELEM_UINT8 0
5826#define DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED 1
5827#define DUK_HBUFFEROBJECT_ELEM_INT8 2
5828#define DUK_HBUFFEROBJECT_ELEM_UINT16 3
5829#define DUK_HBUFFEROBJECT_ELEM_INT16 4
5830#define DUK_HBUFFEROBJECT_ELEM_UINT32 5
5831#define DUK_HBUFFEROBJECT_ELEM_INT32 6
5832#define DUK_HBUFFEROBJECT_ELEM_FLOAT32 7
5833#define DUK_HBUFFEROBJECT_ELEM_FLOAT64 8
5834#define DUK_HBUFFEROBJECT_ELEM_MAX 8
5835
5836#define DUK_ASSERT_HBUFFEROBJECT_VALID(h) do { \
5837 DUK_ASSERT((h) != NULL); \
5838 DUK_ASSERT((h)->shift <= 3); \
5839 DUK_ASSERT((h)->elem_type <= DUK_HBUFFEROBJECT_ELEM_MAX); \
5840 DUK_ASSERT(((h)->shift == 0 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8) || \
5841 ((h)->shift == 0 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED) || \
5842 ((h)->shift == 0 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_INT8) || \
5843 ((h)->shift == 1 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT16) || \
5844 ((h)->shift == 1 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_INT16) || \
5845 ((h)->shift == 2 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT32) || \
5846 ((h)->shift == 2 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_INT32) || \
5847 ((h)->shift == 2 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_FLOAT32) || \
5848 ((h)->shift == 3 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_FLOAT64)); \
5849 DUK_ASSERT((h)->is_view == 0 || (h)->is_view == 1); \
5850 DUK_ASSERT(DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) (h))); \
5851 if ((h)->buf == NULL) { \
5852 DUK_ASSERT((h)->offset == 0); \
5853 DUK_ASSERT((h)->length == 0); \
5854 } else { \
5855 /* No assertions for offset or length; in particular, \
5856 * it's OK for length to be longer than underlying \
5857 * buffer. Just ensure they don't wrap when added. \
5858 */ \
5859 DUK_ASSERT((h)->offset + (h)->length >= (h)->offset); \
5860 } \
5861 } while (0)
5862
5863/* Get the current data pointer (caller must ensure buf != NULL) as a
5864 * duk_uint8_t ptr.
5865 */
5866#define DUK_HBUFFEROBJECT_GET_SLICE_BASE(heap,h) \
5867 (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
5868 (((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR((heap), (h)->buf)) + (h)->offset))
5869
5870/* True if slice is full, i.e. offset is zero and length covers the entire
5871 * buffer. This status may change independently of the duk_hbufferobject if
5872 * the underlying buffer is dynamic and changes without the hbufferobject
5873 * being changed.
5874 */
5875#define DUK_HBUFFEROBJECT_FULL_SLICE(h) \
5876 (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
5877 ((h)->offset == 0 && (h)->length == DUK_HBUFFER_GET_SIZE((h)->buf)))
5878
5879/* Validate that the whole slice [0,length[ is contained in the underlying
5880 * buffer. Caller must ensure 'buf' != NULL.
5881 */
5882#define DUK_HBUFFEROBJECT_VALID_SLICE(h) \
5883 (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
5884 ((h)->offset + (h)->length <= DUK_HBUFFER_GET_SIZE((h)->buf)))
5885
5886/* Validate byte read/write for virtual 'offset', i.e. check that the
5887 * offset, taking into account h->offset, is within the underlying
5888 * buffer size. This is a safety check which is needed to ensure
5889 * that even a misconfigured duk_hbufferobject never causes memory
5890 * unsafe behavior (e.g. if an underlying dynamic buffer changes
5891 * after being setup). Caller must ensure 'buf' != NULL.
5892 */
5893#define DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_INCL(h,off) \
5894 (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
5895 ((h)->offset + (off) < DUK_HBUFFER_GET_SIZE((h)->buf)))
5896
5897#define DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h,off) \
5898 (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
5899 ((h)->offset + (off) <= DUK_HBUFFER_GET_SIZE((h)->buf)))
5900
5901/* Clamp an input byte length (already assumed to be within the nominal
5902 * duk_hbufferobject 'length') to the current dynamic buffer limits to
5903 * yield a byte length limit that's safe for memory accesses. This value
5904 * can be invalidated by any side effect because it may trigger a user
5905 * callback that resizes the underlying buffer.
5906 */
5907#define DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h,len) \
5908 (DUK_ASSERT_EXPR((h) != NULL), \
5909 duk_hbufferobject_clamp_bytelength((h), (len)))
5910
5911struct duk_hbufferobject {
5912 /* Shared object part. */
5913 duk_hobject obj;
5914
5915 /* Underlying buffer (refcounted), may be NULL. */
5916 duk_hbuffer *buf;
5917
5918 /* Slice and accessor information.
5919 *
5920 * Because the underlying buffer may be dynamic, these may be
5921 * invalidated by the buffer being modified so that both offset
5922 * and length should be validated before every access. Behavior
5923 * when the underlying buffer has changed doesn't need to be clean:
5924 * virtual 'length' doesn't need to be affected, reads can return
5925 * zero/NaN, and writes can be ignored.
5926 *
5927 * Note that a data pointer cannot be precomputed because 'buf' may
5928 * be dynamic and its pointer unstable.
5929 */
5930
5931 duk_uint_t offset; /* byte offset to buf */
5932 duk_uint_t length; /* byte index limit for element access, exclusive */
5933 duk_uint8_t shift; /* element size shift:
5934 * 0 = u8/i8
5935 * 1 = u16/i16
5936 * 2 = u32/i32/float
5937 * 3 = double
5938 */
5939 duk_uint8_t elem_type; /* element type */
5940 duk_uint8_t is_view;
5941};
5942
5943#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
5944DUK_INTERNAL_DECL duk_uint_t duk_hbufferobject_clamp_bytelength(duk_hbufferobject *h_bufobj, duk_uint_t len);
5945#endif
5946DUK_INTERNAL_DECL void duk_hbufferobject_push_validated_read(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size);
5947DUK_INTERNAL_DECL void duk_hbufferobject_validated_write(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size);
5948
5949#endif /* DUK_HBUFFEROBJECT_H_INCLUDED */
7c673cae
FG
5950/*
5951 * Heap thread object representation.
5952 *
5953 * duk_hthread is also the 'context' (duk_context) for exposed APIs
5954 * which mostly operate on the topmost frame of the value stack.
5955 */
5956
5957#ifndef DUK_HTHREAD_H_INCLUDED
5958#define DUK_HTHREAD_H_INCLUDED
5959
5960/*
5961 * Stack constants
5962 */
5963
5964#define DUK_VALSTACK_GROW_STEP 128 /* roughly 1 kiB */
5965#define DUK_VALSTACK_SHRINK_THRESHOLD 256 /* roughly 2 kiB */
5966#define DUK_VALSTACK_SHRINK_SPARE 64 /* roughly 0.5 kiB */
5967#define DUK_VALSTACK_INITIAL_SIZE 128 /* roughly 1.0 kiB -> but rounds up to DUK_VALSTACK_GROW_STEP in practice */
5968#define DUK_VALSTACK_INTERNAL_EXTRA 64 /* internal extra elements assumed on function entry,
5969 * always added to user-defined 'extra' for e.g. the
5970 * duk_check_stack() call.
5971 */
5972#define DUK_VALSTACK_API_ENTRY_MINIMUM DUK_API_ENTRY_STACK
5973 /* number of elements guaranteed to be user accessible
5974 * (in addition to call arguments) on Duktape/C function entry.
5975 */
5976
5977/* Note: DUK_VALSTACK_INITIAL_SIZE must be >= DUK_VALSTACK_API_ENTRY_MINIMUM
5978 * + DUK_VALSTACK_INTERNAL_EXTRA so that the initial stack conforms to spare
5979 * requirements.
5980 */
5981
5982#define DUK_VALSTACK_DEFAULT_MAX 1000000L
5983
5984#define DUK_CALLSTACK_GROW_STEP 8 /* roughly 256 bytes */
5985#define DUK_CALLSTACK_SHRINK_THRESHOLD 16 /* roughly 512 bytes */
5986#define DUK_CALLSTACK_SHRINK_SPARE 8 /* roughly 256 bytes */
5987#define DUK_CALLSTACK_INITIAL_SIZE 8
5988#define DUK_CALLSTACK_DEFAULT_MAX 10000L
5989
5990#define DUK_CATCHSTACK_GROW_STEP 4 /* roughly 64 bytes */
5991#define DUK_CATCHSTACK_SHRINK_THRESHOLD 8 /* roughly 128 bytes */
5992#define DUK_CATCHSTACK_SHRINK_SPARE 4 /* roughly 64 bytes */
5993#define DUK_CATCHSTACK_INITIAL_SIZE 4
5994#define DUK_CATCHSTACK_DEFAULT_MAX 10000L
5995
5996/*
5997 * Activation defines
5998 */
5999
6000#define DUK_ACT_FLAG_STRICT (1 << 0) /* function executes in strict mode */
6001#define DUK_ACT_FLAG_TAILCALLED (1 << 1) /* activation has tail called one or more times */
6002#define DUK_ACT_FLAG_CONSTRUCT (1 << 2) /* function executes as a constructor (called via "new") */
6003#define DUK_ACT_FLAG_PREVENT_YIELD (1 << 3) /* activation prevents yield (native call or "new") */
6004#define DUK_ACT_FLAG_DIRECT_EVAL (1 << 4) /* activation is a direct eval call */
6005#define DUK_ACT_FLAG_BREAKPOINT_ACTIVE (1 << 5) /* activation has active breakpoint(s) */
6006
6007#define DUK_ACT_GET_FUNC(act) ((act)->func)
6008
6009/*
6010 * Flags for __FILE__ / __LINE__ registered into tracedata
6011 */
6012
6013#define DUK_TB_FLAG_NOBLAME_FILELINE (1 << 0) /* don't report __FILE__ / __LINE__ as fileName/lineNumber */
6014
6015/*
6016 * Catcher defines
6017 */
6018
6019/* flags field: LLLLLLFT, L = label (24 bits), F = flags (4 bits), T = type (4 bits) */
6020#define DUK_CAT_TYPE_MASK 0x0000000fUL
6021#define DUK_CAT_TYPE_BITS 4
6022#define DUK_CAT_LABEL_MASK 0xffffff00UL
6023#define DUK_CAT_LABEL_BITS 24
6024#define DUK_CAT_LABEL_SHIFT 8
6025
6026#define DUK_CAT_FLAG_CATCH_ENABLED (1 << 4) /* catch part will catch */
6027#define DUK_CAT_FLAG_FINALLY_ENABLED (1 << 5) /* finally part will catch */
6028#define DUK_CAT_FLAG_CATCH_BINDING_ENABLED (1 << 6) /* request to create catch binding */
6029#define DUK_CAT_FLAG_LEXENV_ACTIVE (1 << 7) /* catch or with binding is currently active */
6030
6031#define DUK_CAT_TYPE_UNKNOWN 0
6032#define DUK_CAT_TYPE_TCF 1
6033#define DUK_CAT_TYPE_LABEL 2
6034
6035#define DUK_CAT_GET_TYPE(c) ((c)->flags & DUK_CAT_TYPE_MASK)
6036#define DUK_CAT_GET_LABEL(c) (((c)->flags & DUK_CAT_LABEL_MASK) >> DUK_CAT_LABEL_SHIFT)
6037
6038#define DUK_CAT_HAS_CATCH_ENABLED(c) ((c)->flags & DUK_CAT_FLAG_CATCH_ENABLED)
6039#define DUK_CAT_HAS_FINALLY_ENABLED(c) ((c)->flags & DUK_CAT_FLAG_FINALLY_ENABLED)
6040#define DUK_CAT_HAS_CATCH_BINDING_ENABLED(c) ((c)->flags & DUK_CAT_FLAG_CATCH_BINDING_ENABLED)
6041#define DUK_CAT_HAS_LEXENV_ACTIVE(c) ((c)->flags & DUK_CAT_FLAG_LEXENV_ACTIVE)
6042
6043#define DUK_CAT_SET_CATCH_ENABLED(c) do { \
6044 (c)->flags |= DUK_CAT_FLAG_CATCH_ENABLED; \
6045 } while (0)
6046#define DUK_CAT_SET_FINALLY_ENABLED(c) do { \
6047 (c)->flags |= DUK_CAT_FLAG_FINALLY_ENABLED; \
6048 } while (0)
6049#define DUK_CAT_SET_CATCH_BINDING_ENABLED(c) do { \
6050 (c)->flags |= DUK_CAT_FLAG_CATCH_BINDING_ENABLED; \
6051 } while (0)
6052#define DUK_CAT_SET_LEXENV_ACTIVE(c) do { \
6053 (c)->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE; \
6054 } while (0)
6055
6056#define DUK_CAT_CLEAR_CATCH_ENABLED(c) do { \
6057 (c)->flags &= ~DUK_CAT_FLAG_CATCH_ENABLED; \
6058 } while (0)
6059#define DUK_CAT_CLEAR_FINALLY_ENABLED(c) do { \
6060 (c)->flags &= ~DUK_CAT_FLAG_FINALLY_ENABLED; \
6061 } while (0)
6062#define DUK_CAT_CLEAR_CATCH_BINDING_ENABLED(c) do { \
6063 (c)->flags &= ~DUK_CAT_FLAG_CATCH_BINDING_ENABLED; \
6064 } while (0)
6065#define DUK_CAT_CLEAR_LEXENV_ACTIVE(c) do { \
6066 (c)->flags &= ~DUK_CAT_FLAG_LEXENV_ACTIVE; \
6067 } while (0)
6068
6069/*
6070 * Thread defines
6071 */
6072
11fdf7f2
TL
6073#if defined(DUK_USE_ROM_STRINGS)
6074#define DUK_HTHREAD_GET_STRING(thr,idx) \
6075 ((duk_hstring *) DUK_LOSE_CONST(duk_rom_strings_stridx[(idx)]))
6076#else /* DUK_USE_ROM_STRINGS */
7c673cae
FG
6077#if defined(DUK_USE_HEAPPTR16)
6078#define DUK_HTHREAD_GET_STRING(thr,idx) \
6079 ((duk_hstring *) DUK_USE_HEAPPTR_DEC16((thr)->heap->heap_udata, (thr)->strs16[(idx)]))
6080#else
6081#define DUK_HTHREAD_GET_STRING(thr,idx) \
6082 ((thr)->strs[(idx)])
6083#endif
11fdf7f2 6084#endif /* DUK_USE_ROM_STRINGS */
7c673cae
FG
6085
6086#define DUK_HTHREAD_GET_CURRENT_ACTIVATION(thr) (&(thr)->callstack[(thr)->callstack_top - 1])
6087
6088/* values for the state field */
6089#define DUK_HTHREAD_STATE_INACTIVE 1 /* thread not currently running */
6090#define DUK_HTHREAD_STATE_RUNNING 2 /* thread currently running (only one at a time) */
6091#define DUK_HTHREAD_STATE_RESUMED 3 /* thread resumed another thread (active but not running) */
6092#define DUK_HTHREAD_STATE_YIELDED 4 /* thread has yielded */
6093#define DUK_HTHREAD_STATE_TERMINATED 5 /* thread has terminated */
6094
6095/* Executor interrupt default interval when nothing else requires a
6096 * smaller value. The default interval must be small enough to allow
6097 * for reasonable execution timeout checking but large enough to keep
6098 * impact on execution performance low.
6099 */
6100#if defined(DUK_USE_INTERRUPT_COUNTER)
6101#define DUK_HTHREAD_INTCTR_DEFAULT (256L * 1024L)
6102#endif
6103
6104/*
6105 * Assert context is valid: non-NULL pointer, fields look sane.
6106 *
6107 * This is used by public API call entrypoints to catch invalid 'ctx' pointers
6108 * as early as possible; invalid 'ctx' pointers cause very odd and difficult to
6109 * diagnose behavior so it's worth checking even when the check is not 100%.
6110 */
6111
11fdf7f2
TL
6112#if defined(DUK_USE_PREFER_SIZE)
6113#define DUK_ASSERT_CTX_VSSIZE(ctx) /*nop*/
6114#else
6115#define DUK_ASSERT_CTX_VSSIZE(ctx) \
6116 DUK_ASSERT((duk_size_t) (((duk_hthread *) (ctx))->valstack_end - ((duk_hthread *) (ctx))->valstack) == \
6117 ((duk_hthread *) (ctx))->valstack_size)
6118#endif
7c673cae
FG
6119#define DUK_ASSERT_CTX_VALID(ctx) do { \
6120 DUK_ASSERT((ctx) != NULL); \
6121 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) (ctx)) == DUK_HTYPE_OBJECT); \
6122 DUK_ASSERT(DUK_HOBJECT_IS_THREAD((duk_hobject *) (ctx))); \
6123 DUK_ASSERT(((duk_hthread *) (ctx))->unused1 == 0); \
6124 DUK_ASSERT(((duk_hthread *) (ctx))->unused2 == 0); \
6125 DUK_ASSERT(((duk_hthread *) (ctx))->valstack != NULL); \
6126 DUK_ASSERT(((duk_hthread *) (ctx))->valstack_end >= ((duk_hthread *) (ctx))->valstack); \
6127 DUK_ASSERT(((duk_hthread *) (ctx))->valstack_top >= ((duk_hthread *) (ctx))->valstack); \
6128 DUK_ASSERT(((duk_hthread *) (ctx))->valstack_top >= ((duk_hthread *) (ctx))->valstack_bottom); \
11fdf7f2
TL
6129 DUK_ASSERT(((duk_hthread *) (ctx))->valstack_end >= ((duk_hthread *) (ctx))->valstack_top); \
6130 DUK_ASSERT_CTX_VSSIZE((ctx)); \
7c673cae
FG
6131 } while (0)
6132
6133/*
6134 * Struct defines
6135 */
6136
6137/* XXX: for a memory-code tradeoff, remove 'func' and make it's access either a function
6138 * or a macro. This would make the activation 32 bytes long on 32-bit platforms again.
6139 */
6140
6141/* Note: it's nice if size is 2^N (at least for 32-bit platforms). */
6142struct duk_activation {
6143 duk_tval tv_func; /* borrowed: full duk_tval for function being executed; for lightfuncs */
6144 duk_hobject *func; /* borrowed: function being executed; for bound function calls, this is the final, real function, NULL for lightfuncs */
6145 duk_hobject *var_env; /* current variable environment (may be NULL if delayed) */
6146 duk_hobject *lex_env; /* current lexical environment (may be NULL if delayed) */
6147#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
6148 /* Previous value of 'func' caller, restored when unwound. Only in use
6149 * when 'func' is non-strict.
6150 */
6151 duk_hobject *prev_caller;
6152#endif
6153
6154 duk_instr_t *curr_pc; /* next instruction to execute (points to 'func' bytecode, stable pointer), NULL for native calls */
6155#if defined(DUK_USE_DEBUGGER_SUPPORT)
6156 duk_uint32_t prev_line; /* needed for stepping */
6157#endif
6158 duk_small_uint_t flags;
6159
6160 /* idx_bottom and idx_retval are only used for book-keeping of
6161 * Ecmascript-initiated calls, to allow returning to an Ecmascript
6162 * function properly. They are duk_size_t to match the convention
6163 * that value stack sizes are duk_size_t and local frame indices
6164 * are duk_idx_t.
6165 */
6166
6167 /* Bottom of valstack for this activation, used to reset
6168 * valstack_bottom on return; index is absolute. Note:
6169 * idx_top not needed because top is set to 'nregs' always
6170 * when returning to an Ecmascript activation.
6171 */
6172 duk_size_t idx_bottom;
6173
6174 /* Return value when returning to this activation (points to caller
6175 * reg, not callee reg); index is absolute (only set if activation is
6176 * not topmost).
6177 *
6178 * Note: idx_bottom is always set, while idx_retval is only applicable
6179 * for activations below the topmost one. Currently idx_retval for
6180 * the topmost activation is considered garbage (and it not initialized
6181 * on entry or cleared on return; may contain previous or garbage
6182 * values).
6183 */
6184 duk_size_t idx_retval;
6185
6186 /* Current 'this' binding is the value just below idx_bottom.
6187 * Previously, 'this' binding was handled with an index to the
6188 * (calling) valstack. This works for everything except tail
6189 * calls, which must not "cumulate" valstack temps.
6190 */
6191};
6192
6193/* Note: it's nice if size is 2^N (not 4x4 = 16 bytes on 32 bit) */
6194struct duk_catcher {
6195 duk_hstring *h_varname; /* borrowed reference to catch variable name (or NULL if none) */
6196 /* (reference is valid as long activation exists) */
6197 duk_instr_t *pc_base; /* resume execution from pc_base or pc_base+1 (points to 'func' bytecode, stable pointer) */
6198 duk_size_t callstack_index; /* callstack index of related activation */
6199 duk_size_t idx_base; /* idx_base and idx_base+1 get completion value and type */
6200 duk_uint32_t flags; /* type and control flags, label number */
6201};
6202
6203struct duk_hthread {
6204 /* Shared object part */
6205 duk_hobject obj;
6206
6207 /* Pointer to bytecode executor's 'curr_pc' variable. Used to copy
6208 * the current PC back into the topmost activation when activation
6209 * state is about to change (or "syncing" is otherwise needed). This
6210 * is rather awkward but important for performance, see execution.rst.
6211 */
6212 duk_instr_t **ptr_curr_pc;
6213
11fdf7f2 6214 /* Backpointers. */
7c673cae
FG
6215 duk_heap *heap;
6216
11fdf7f2 6217 /* Current strictness flag: affects API calls. */
7c673cae 6218 duk_uint8_t strict;
11fdf7f2
TL
6219
6220 /* Thread state. */
7c673cae
FG
6221 duk_uint8_t state;
6222 duk_uint8_t unused1;
6223 duk_uint8_t unused2;
6224
11fdf7f2 6225 /* Sanity limits for stack sizes. */
7c673cae
FG
6226 duk_size_t valstack_max;
6227 duk_size_t callstack_max;
6228 duk_size_t catchstack_max;
6229
11fdf7f2 6230 /* XXX: Valstack, callstack, and catchstack are currently assumed
7c673cae
FG
6231 * to have non-NULL pointers. Relaxing this would not lead to big
6232 * benefits (except perhaps for terminated threads).
6233 */
6234
11fdf7f2
TL
6235 /* Value stack: these are expressed as pointers for faster stack manipulation.
6236 * [valstack,valstack_top[ is GC-reachable, [valstack_top,valstack_end[ is
6237 * not GC-reachable but kept initialized as 'undefined'.
6238 */
7c673cae
FG
6239 duk_tval *valstack; /* start of valstack allocation */
6240 duk_tval *valstack_end; /* end of valstack allocation (exclusive) */
6241 duk_tval *valstack_bottom; /* bottom of current frame */
6242 duk_tval *valstack_top; /* top of current frame (exclusive) */
11fdf7f2
TL
6243#if !defined(DUK_USE_PREFER_SIZE)
6244 duk_size_t valstack_size; /* cached: valstack_end - valstack (in entries, not bytes) */
6245#endif
7c673cae 6246
11fdf7f2 6247 /* Call stack. [0,callstack_top[ is GC reachable. */
7c673cae
FG
6248 duk_activation *callstack;
6249 duk_size_t callstack_size; /* allocation size */
6250 duk_size_t callstack_top; /* next to use, highest used is top - 1 */
6251 duk_size_t callstack_preventcount; /* number of activation records in callstack preventing a yield */
6252
11fdf7f2 6253 /* Catch stack. [0,catchstack_top[ is GC reachable. */
7c673cae
FG
6254 duk_catcher *catchstack;
6255 duk_size_t catchstack_size; /* allocation size */
6256 duk_size_t catchstack_top; /* next to use, highest used is top - 1 */
6257
11fdf7f2 6258 /* Yield/resume book-keeping. */
7c673cae
FG
6259 duk_hthread *resumer; /* who resumed us (if any) */
6260
11fdf7f2 6261 /* Current compiler state (if any), used for augmenting SyntaxErrors. */
7c673cae
FG
6262 duk_compiler_ctx *compile_ctx;
6263
6264#if defined(DUK_USE_INTERRUPT_COUNTER)
6265 /* Interrupt counter for triggering a slow path check for execution
6266 * timeout, debugger interaction such as breakpoints, etc. The value
6267 * is valid for the current running thread, and both the init and
6268 * counter values are copied whenever a thread switch occurs. It's
6269 * important for the counter to be conveniently accessible for the
6270 * bytecode executor inner loop for performance reasons.
6271 */
6272 duk_int_t interrupt_counter; /* countdown state */
6273 duk_int_t interrupt_init; /* start value for current countdown */
6274#endif
6275
6276 /* Builtin-objects; may or may not be shared with other threads,
6277 * threads existing in different "compartments" will have different
6278 * built-ins. Must be stored on a per-thread basis because there
6279 * is no intermediate structure for a thread group / compartment.
6280 * This takes quite a lot of space, currently 43x4 = 172 bytes on
6281 * 32-bit platforms.
11fdf7f2
TL
6282 *
6283 * In some cases the builtins array could be ROM based, but it's
6284 * sometimes edited (e.g. for sandboxing) so it's better to keep
6285 * this array in RAM.
7c673cae
FG
6286 */
6287 duk_hobject *builtins[DUK_NUM_BUILTINS];
6288
11fdf7f2
TL
6289 /* Convenience copies from heap/vm for faster access. */
6290#if defined(DUK_USE_ROM_STRINGS)
6291 /* No field needed when strings are in ROM. */
6292#else
7c673cae
FG
6293#if defined(DUK_USE_HEAPPTR16)
6294 duk_uint16_t *strs16;
6295#else
6296 duk_hstring **strs;
6297#endif
11fdf7f2 6298#endif
7c673cae
FG
6299};
6300
6301/*
6302 * Prototypes
6303 */
6304
6305DUK_INTERNAL_DECL void duk_hthread_copy_builtin_objects(duk_hthread *thr_from, duk_hthread *thr_to);
6306DUK_INTERNAL_DECL void duk_hthread_create_builtin_objects(duk_hthread *thr);
6307DUK_INTERNAL_DECL duk_bool_t duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr);
6308DUK_INTERNAL_DECL void duk_hthread_terminate(duk_hthread *thr);
6309
6310DUK_INTERNAL_DECL void duk_hthread_callstack_grow(duk_hthread *thr);
6311DUK_INTERNAL_DECL void duk_hthread_callstack_shrink_check(duk_hthread *thr);
6312DUK_INTERNAL_DECL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_top);
6313DUK_INTERNAL_DECL void duk_hthread_catchstack_grow(duk_hthread *thr);
6314DUK_INTERNAL_DECL void duk_hthread_catchstack_shrink_check(duk_hthread *thr);
6315DUK_INTERNAL_DECL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new_top);
6316
6317DUK_INTERNAL_DECL duk_activation *duk_hthread_get_current_activation(duk_hthread *thr);
6318DUK_INTERNAL_DECL void *duk_hthread_get_valstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */
6319DUK_INTERNAL_DECL void *duk_hthread_get_callstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */
6320DUK_INTERNAL_DECL void *duk_hthread_get_catchstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */
6321
6322#if defined(DUK_USE_DEBUGGER_SUPPORT)
6323DUK_INTERNAL_DECL duk_uint_fast32_t duk_hthread_get_act_curr_pc(duk_hthread *thr, duk_activation *act);
6324#endif
6325DUK_INTERNAL_DECL duk_uint_fast32_t duk_hthread_get_act_prev_pc(duk_hthread *thr, duk_activation *act);
6326DUK_INTERNAL_DECL void duk_hthread_sync_currpc(duk_hthread *thr);
6327DUK_INTERNAL_DECL void duk_hthread_sync_and_null_currpc(duk_hthread *thr);
6328
6329#endif /* DUK_HTHREAD_H_INCLUDED */
7c673cae
FG
6330/*
6331 * Heap buffer representation.
6332 *
6333 * Heap allocated user data buffer which is either:
6334 *
6335 * 1. A fixed size buffer (data follows header statically)
6336 * 2. A dynamic size buffer (data pointer follows header)
6337 *
6338 * The data pointer for a variable size buffer of zero size may be NULL.
6339 */
6340
6341#ifndef DUK_HBUFFER_H_INCLUDED
6342#define DUK_HBUFFER_H_INCLUDED
6343
6344/*
6345 * Flags
6346 *
6347 * Fixed buffer: 0
6348 * Dynamic buffer: DUK_HBUFFER_FLAG_DYNAMIC
6349 * External buffer: DUK_HBUFFER_FLAG_DYNAMIC | DUK_HBUFFER_FLAG_EXTERNAL
6350 */
6351
6352#define DUK_HBUFFER_FLAG_DYNAMIC DUK_HEAPHDR_USER_FLAG(0) /* buffer is behind a pointer, dynamic or external */
6353#define DUK_HBUFFER_FLAG_EXTERNAL DUK_HEAPHDR_USER_FLAG(1) /* buffer pointer is to an externally allocated buffer */
6354
6355#define DUK_HBUFFER_HAS_DYNAMIC(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC)
6356#define DUK_HBUFFER_HAS_EXTERNAL(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL)
6357
6358#define DUK_HBUFFER_SET_DYNAMIC(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC)
6359#define DUK_HBUFFER_SET_EXTERNAL(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL)
6360
6361#define DUK_HBUFFER_CLEAR_DYNAMIC(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC)
6362#define DUK_HBUFFER_CLEAR_EXTERNAL(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL)
6363
6364/*
6365 * Misc defines
6366 */
6367
6368/* Impose a maximum buffer length for now. Restricted artificially to
6369 * ensure resize computations or adding a heap header length won't
6370 * overflow size_t and that a signed duk_int_t can hold a buffer
6371 * length. The limit should be synchronized with DUK_HSTRING_MAX_BYTELEN.
6372 */
6373
6374#if defined(DUK_USE_BUFLEN16)
6375#define DUK_HBUFFER_MAX_BYTELEN (0x0000ffffUL)
6376#else
6377/* Intentionally not 0x7fffffffUL; at least JSON code expects that
6378 * 2*len + 2 fits in 32 bits.
6379 */
6380#define DUK_HBUFFER_MAX_BYTELEN (0x7ffffffeUL)
6381#endif
6382
6383/*
6384 * Field access
6385 */
6386
6387/* Get/set the current user visible size, without accounting for a dynamic
6388 * buffer's "spare" (= usable size).
6389 */
6390#if defined(DUK_USE_BUFLEN16)
6391/* size stored in duk_heaphdr unused flag bits */
6392#define DUK_HBUFFER_GET_SIZE(x) ((x)->hdr.h_flags >> 16)
6393#define DUK_HBUFFER_SET_SIZE(x,v) do { \
11fdf7f2
TL
6394 duk_size_t duk__v; \
6395 duk__v = (v); \
6396 DUK_ASSERT(duk__v <= 0xffffUL); \
6397 (x)->hdr.h_flags = ((x)->hdr.h_flags & 0x0000ffffUL) | (((duk_uint32_t) duk__v) << 16); \
7c673cae
FG
6398 } while (0)
6399#define DUK_HBUFFER_ADD_SIZE(x,dv) do { \
6400 (x)->hdr.h_flags += ((dv) << 16); \
6401 } while (0)
6402#define DUK_HBUFFER_SUB_SIZE(x,dv) do { \
6403 (x)->hdr.h_flags -= ((dv) << 16); \
6404 } while (0)
6405#else
6406#define DUK_HBUFFER_GET_SIZE(x) (((duk_hbuffer *) (x))->size)
6407#define DUK_HBUFFER_SET_SIZE(x,v) do { \
6408 ((duk_hbuffer *) (x))->size = (v); \
6409 } while (0)
6410#define DUK_HBUFFER_ADD_SIZE(x,dv) do { \
6411 (x)->size += (dv); \
6412 } while (0)
6413#define DUK_HBUFFER_SUB_SIZE(x,dv) do { \
6414 (x)->size -= (dv); \
6415 } while (0)
6416#endif
6417
6418#define DUK_HBUFFER_FIXED_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x))
6419#define DUK_HBUFFER_FIXED_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x))
6420
6421#define DUK_HBUFFER_DYNAMIC_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x))
6422#define DUK_HBUFFER_DYNAMIC_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x), (v))
6423#define DUK_HBUFFER_DYNAMIC_ADD_SIZE(x,dv) DUK_HBUFFER_ADD_SIZE((duk_hbuffer *) (x), (dv))
6424#define DUK_HBUFFER_DYNAMIC_SUB_SIZE(x,dv) DUK_HBUFFER_SUB_SIZE((duk_hbuffer *) (x), (dv))
6425
6426#define DUK_HBUFFER_EXTERNAL_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x))
6427#define DUK_HBUFFER_EXTERNAL_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x), (v))
6428
6429#define DUK_HBUFFER_FIXED_GET_DATA_PTR(heap,x) ((duk_uint8_t *) (((duk_hbuffer_fixed *) (x)) + 1))
6430
6431#if defined(DUK_USE_HEAPPTR16)
6432#define DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap,x) \
6433 ((void *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, ((duk_heaphdr *) (x))->h_extra16))
6434#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap,x,v) do { \
6435 ((duk_heaphdr *) (x))->h_extra16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
6436 } while (0)
6437#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(heap,x) do { \
6438 ((duk_heaphdr *) (x))->h_extra16 = 0; /* assume 0 <=> NULL */ \
6439 } while (0)
6440#else
6441#define DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap,x) ((x)->curr_alloc)
6442#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap,x,v) do { \
6443 (x)->curr_alloc = (void *) (v); \
6444 } while (0)
6445#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(heap,x) do { \
6446 (x)->curr_alloc = (void *) NULL; \
6447 } while (0)
6448#endif
6449
6450/* No pointer compression because pointer is potentially outside of
6451 * Duktape heap.
6452 */
6453#if defined(DUK_USE_HEAPPTR16)
6454#define DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap,x) \
6455 ((void *) (x)->curr_alloc)
6456#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap,x,v) do { \
6457 (x)->curr_alloc = (void *) (v); \
6458 } while (0)
6459#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR_NULL(heap,x) do { \
6460 (x)->curr_alloc = (void *) NULL; \
6461 } while (0)
6462#else
6463#define DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap,x) \
6464 ((void *) (x)->curr_alloc)
6465#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap,x,v) do { \
6466 (x)->curr_alloc = (void *) (v); \
6467 } while (0)
6468#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR_NULL(heap,x) do { \
6469 (x)->curr_alloc = (void *) NULL; \
6470 } while (0)
6471#endif
6472
6473/* Get a pointer to the current buffer contents (matching current allocation
6474 * size). May be NULL for zero size dynamic/external buffer.
6475 */
6476#if defined(DUK_USE_HEAPPTR16)
6477#define DUK_HBUFFER_GET_DATA_PTR(heap,x) ( \
6478 DUK_HBUFFER_HAS_DYNAMIC((x)) ? \
6479 ( \
6480 DUK_HBUFFER_HAS_EXTERNAL((x)) ? \
6481 DUK_HBUFFER_EXTERNAL_GET_DATA_PTR((heap), (duk_hbuffer_external *) (x)) : \
6482 DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((heap), (duk_hbuffer_dynamic *) (x)) \
6483 ) : \
6484 DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), (duk_hbuffer_fixed *) (x)) \
6485 )
6486#else
6487/* Without heap pointer compression duk_hbuffer_dynamic and duk_hbuffer_external
6488 * have the same layout so checking for fixed vs. dynamic (or external) is enough.
6489 */
6490#define DUK_HBUFFER_GET_DATA_PTR(heap,x) ( \
6491 DUK_HBUFFER_HAS_DYNAMIC((x)) ? \
6492 DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((heap), (duk_hbuffer_dynamic *) (x)) : \
6493 DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), (duk_hbuffer_fixed *) (x)) \
6494 )
6495#endif
6496
6497/*
6498 * Structs
6499 */
6500
6501/* Shared prefix for all buffer types. */
6502struct duk_hbuffer {
6503 duk_heaphdr hdr;
6504
6505 /* It's not strictly necessary to track the current size, but
6506 * it is useful for writing robust native code.
6507 */
6508
6509 /* Current size (not counting a dynamic buffer's "spare"). */
6510#if defined(DUK_USE_BUFLEN16)
6511 /* Stored in duk_heaphdr unused flags. */
6512#else
6513 duk_size_t size;
6514#endif
6515
6516 /*
6517 * Data following the header depends on the DUK_HBUFFER_FLAG_DYNAMIC
6518 * flag.
6519 *
6520 * If the flag is clear (the buffer is a fixed size one), the buffer
6521 * data follows the header directly, consisting of 'size' bytes.
6522 *
6523 * If the flag is set, the actual buffer is allocated separately, and
6524 * a few control fields follow the header. Specifically:
6525 *
6526 * - a "void *" pointing to the current allocation
6527 * - a duk_size_t indicating the full allocated size (always >= 'size')
6528 *
6529 * If DUK_HBUFFER_FLAG_EXTERNAL is set, the buffer has been allocated
6530 * by user code, so that Duktape won't be able to resize it and won't
6531 * free it. This allows buffers to point to e.g. an externally
6532 * allocated structure such as a frame buffer.
6533 *
6534 * Unlike strings, no terminator byte (NUL) is guaranteed after the
6535 * data. This would be convenient, but would pad aligned user buffers
6536 * unnecessarily upwards in size. For instance, if user code requested
6537 * a 64-byte dynamic buffer, 65 bytes would actually be allocated which
6538 * would then potentially round upwards to perhaps 68 or 72 bytes.
6539 */
6540};
6541
6542/* Fixed buffer; data follows struct, with proper alignment guaranteed by
6543 * struct size.
6544 */
6545#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_MSVC_PRAGMA)
6546#pragma pack(push, 8)
6547#endif
6548struct duk_hbuffer_fixed {
6549 /* A union is used here as a portable struct size / alignment trick:
6550 * by adding a 32-bit or a 64-bit (unused) union member, the size of
6551 * the struct is effectively forced to be a multiple of 4 or 8 bytes
6552 * (respectively) without increasing the size of the struct unless
6553 * necessary.
6554 */
6555 union {
6556 struct {
6557 duk_heaphdr hdr;
6558#if defined(DUK_USE_BUFLEN16)
6559 /* Stored in duk_heaphdr unused flags. */
6560#else
6561 duk_size_t size;
6562#endif
6563 } s;
6564#if (DUK_USE_ALIGN_BY == 4)
6565 duk_uint32_t dummy_for_align4;
6566#elif (DUK_USE_ALIGN_BY == 8)
6567 duk_double_t dummy_for_align8;
6568#elif (DUK_USE_ALIGN_BY == 1)
6569 /* no extra padding */
6570#else
6571#error invalid DUK_USE_ALIGN_BY
6572#endif
6573 } u;
6574
6575 /*
6576 * Data follows the struct header. The struct size is padded by the
6577 * compiler based on the struct members. This guarantees that the
6578 * buffer data will be aligned-by-4 but not necessarily aligned-by-8.
6579 *
6580 * On platforms where alignment does not matter, the struct padding
6581 * could be removed (if there is any). On platforms where alignment
6582 * by 8 is required, the struct size must be forced to be a multiple
6583 * of 8 by some means. Without it, some user code may break, and also
6584 * Duktape itself breaks (e.g. the compiler stores duk_tvals in a
6585 * dynamic buffer).
6586 */
6587}
6588#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_GCC_ATTR)
6589__attribute__ ((aligned (8)))
6590#elif (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_CLANG_ATTR)
6591__attribute__ ((aligned (8)))
6592#endif
6593;
6594#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_MSVC_PRAGMA)
6595#pragma pack(pop)
6596#endif
6597
6598/* Dynamic buffer with 'curr_alloc' pointing to a dynamic area allocated using
6599 * heap allocation primitives. Also used for external buffers when low memory
6600 * options are not used.
6601 */
6602struct duk_hbuffer_dynamic {
6603 duk_heaphdr hdr;
6604
6605#if defined(DUK_USE_BUFLEN16)
6606 /* Stored in duk_heaphdr unused flags. */
6607#else
6608 duk_size_t size;
6609#endif
6610
6611#if defined(DUK_USE_HEAPPTR16)
6612 /* Stored in duk_heaphdr h_extra16. */
6613#else
6614 void *curr_alloc; /* may be NULL if alloc_size == 0 */
6615#endif
6616
6617 /*
6618 * Allocation size for 'curr_alloc' is alloc_size. There is no
6619 * automatic NUL terminator for buffers (see above for rationale).
6620 *
6621 * 'curr_alloc' is explicitly allocated with heap allocation
6622 * primitives and will thus always have alignment suitable for
6623 * e.g. duk_tval and an IEEE double.
6624 */
6625};
6626
6627/* External buffer with 'curr_alloc' managed by user code and pointing to an
6628 * arbitrary address. When heap pointer compression is not used, this struct
6629 * has the same layout as duk_hbuffer_dynamic.
6630 */
6631struct duk_hbuffer_external {
6632 duk_heaphdr hdr;
6633
6634#if defined(DUK_USE_BUFLEN16)
6635 /* Stored in duk_heaphdr unused flags. */
6636#else
6637 duk_size_t size;
6638#endif
6639
6640 /* Cannot be compressed as a heap pointer because may point to
6641 * an arbitrary address.
6642 */
6643 void *curr_alloc; /* may be NULL if alloc_size == 0 */
6644};
6645
6646/*
6647 * Prototypes
6648 */
6649
6650DUK_INTERNAL_DECL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk_small_uint_t flags, void **out_bufdata);
6651DUK_INTERNAL_DECL void *duk_hbuffer_get_dynalloc_ptr(duk_heap *heap, void *ud); /* indirect allocs */
6652
6653/* dynamic buffer ops */
6654DUK_INTERNAL_DECL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_size_t new_size);
6655DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *buf);
6656
6657#endif /* DUK_HBUFFER_H_INCLUDED */
7c673cae
FG
6658/*
6659 * Heap structure.
6660 *
6661 * Heap contains allocated heap objects, interned strings, and built-in
6662 * strings for one or more threads.
6663 */
6664
6665#ifndef DUK_HEAP_H_INCLUDED
6666#define DUK_HEAP_H_INCLUDED
6667
6668/* alloc function typedefs in duktape.h */
6669
6670/*
6671 * Heap flags
6672 */
6673
6674#define DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING (1 << 0) /* mark-and-sweep is currently running */
6675#define DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED (1 << 1) /* mark-and-sweep marking reached a recursion limit and must use multi-pass marking */
6676#define DUK_HEAP_FLAG_REFZERO_FREE_RUNNING (1 << 2) /* refcount code is processing refzero list */
6677#define DUK_HEAP_FLAG_ERRHANDLER_RUNNING (1 << 3) /* an error handler (user callback to augment/replace error) is running */
6678#define DUK_HEAP_FLAG_INTERRUPT_RUNNING (1 << 4) /* executor interrupt running (used to avoid nested interrupts) */
11fdf7f2 6679#define DUK_HEAP_FLAG_FINALIZER_NORESCUE (1 << 5) /* heap destruction ongoing, finalizer rescue no longer possible */
7c673cae
FG
6680
6681#define DUK__HEAP_HAS_FLAGS(heap,bits) ((heap)->flags & (bits))
6682#define DUK__HEAP_SET_FLAGS(heap,bits) do { \
6683 (heap)->flags |= (bits); \
6684 } while (0)
6685#define DUK__HEAP_CLEAR_FLAGS(heap,bits) do { \
6686 (heap)->flags &= ~(bits); \
6687 } while (0)
6688
6689#define DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING)
6690#define DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
6691#define DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING)
6692#define DUK_HEAP_HAS_ERRHANDLER_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING)
6693#define DUK_HEAP_HAS_INTERRUPT_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
11fdf7f2 6694#define DUK_HEAP_HAS_FINALIZER_NORESCUE(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
7c673cae
FG
6695
6696#define DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING)
6697#define DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
6698#define DUK_HEAP_SET_REFZERO_FREE_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING)
6699#define DUK_HEAP_SET_ERRHANDLER_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING)
6700#define DUK_HEAP_SET_INTERRUPT_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
11fdf7f2 6701#define DUK_HEAP_SET_FINALIZER_NORESCUE(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
7c673cae
FG
6702
6703#define DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING)
6704#define DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
6705#define DUK_HEAP_CLEAR_REFZERO_FREE_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING)
6706#define DUK_HEAP_CLEAR_ERRHANDLER_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING)
6707#define DUK_HEAP_CLEAR_INTERRUPT_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
11fdf7f2 6708#define DUK_HEAP_CLEAR_FINALIZER_NORESCUE(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
7c673cae
FG
6709
6710/*
6711 * Longjmp types, also double as identifying continuation type for a rethrow (in 'finally')
6712 */
6713
6714#define DUK_LJ_TYPE_UNKNOWN 0 /* unused */
11fdf7f2
TL
6715#define DUK_LJ_TYPE_THROW 1 /* value1 -> error object */
6716#define DUK_LJ_TYPE_YIELD 2 /* value1 -> yield value, iserror -> error / normal */
6717#define DUK_LJ_TYPE_RESUME 3 /* value1 -> resume value, value2 -> resumee thread, iserror -> error/normal */
6718#define DUK_LJ_TYPE_BREAK 4 /* value1 -> label number, pseudo-type to indicate a break continuation (for ENDFIN) */
6719#define DUK_LJ_TYPE_CONTINUE 5 /* value1 -> label number, pseudo-type to indicate a continue continuation (for ENDFIN) */
6720#define DUK_LJ_TYPE_RETURN 6 /* value1 -> return value, pseudo-type to indicate a return continuation (for ENDFIN) */
6721#define DUK_LJ_TYPE_NORMAL 7 /* no value, pseudo-type to indicate a normal continuation (for ENDFIN) */
7c673cae
FG
6722
6723/*
6724 * Mark-and-sweep flags
6725 *
6726 * These are separate from heap level flags now but could be merged.
6727 * The heap structure only contains a 'base mark-and-sweep flags'
6728 * field and the GC caller can impose further flags.
6729 */
6730
6731#define DUK_MS_FLAG_EMERGENCY (1 << 0) /* emergency mode: try extra hard */
6732#define DUK_MS_FLAG_NO_STRINGTABLE_RESIZE (1 << 1) /* don't resize stringtable (but may sweep it); needed during stringtable resize */
11fdf7f2
TL
6733#define DUK_MS_FLAG_NO_OBJECT_COMPACTION (1 << 2) /* don't compact objects; needed during object property allocation resize */
6734#define DUK_MS_FLAG_NO_FINALIZERS (1 << 3) /* don't run finalizers; leave finalizable objects in finalize_list for next round */
6735#define DUK_MS_FLAG_SKIP_FINALIZERS (1 << 4) /* don't run finalizers; queue finalizable objects back to heap_allocated */
7c673cae
FG
6736
6737/*
6738 * Thread switching
6739 *
6740 * To switch heap->curr_thread, use the macro below so that interrupt counters
6741 * get updated correctly. The macro allows a NULL target thread because that
6742 * happens e.g. in call handling.
6743 */
6744
6745#if defined(DUK_USE_INTERRUPT_COUNTER)
6746#define DUK_HEAP_SWITCH_THREAD(heap,newthr) duk_heap_switch_thread((heap), (newthr))
6747#else
6748#define DUK_HEAP_SWITCH_THREAD(heap,newthr) do { \
6749 (heap)->curr_thread = (newthr); \
6750 } while (0)
6751#endif
6752
6753/*
6754 * Other heap related defines
6755 */
6756
6757/* Mark-and-sweep interval is relative to combined count of objects and
6758 * strings kept in the heap during the latest mark-and-sweep pass.
6759 * Fixed point .8 multiplier and .0 adder. Trigger count (interval) is
6760 * decreased by each (re)allocation attempt (regardless of size), and each
6761 * refzero processed object.
6762 *
6763 * 'SKIP' indicates how many (re)allocations to wait until a retry if
6764 * GC is skipped because there is no thread do it with yet (happens
6765 * only during init phases).
6766 */
6767#if defined(DUK_USE_MARK_AND_SWEEP)
6768#if defined(DUK_USE_REFERENCE_COUNTING)
6769#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT 12800L /* 50x heap size */
6770#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD 1024L
6771#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP 256L
6772#else
6773#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT 256L /* 1x heap size */
6774#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD 1024L
6775#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP 256L
6776#endif
6777#endif
6778
6779/* Stringcache is used for speeding up char-offset-to-byte-offset
6780 * translations for non-ASCII strings.
6781 */
6782#define DUK_HEAP_STRCACHE_SIZE 4
6783#define DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT 16 /* strings up to the this length are not cached */
6784
6785/* helper to insert a (non-string) heap object into heap allocated list */
6786#define DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap,hdr) duk_heap_insert_into_heap_allocated((heap),(hdr))
6787
6788/*
6789 * Stringtable
6790 */
6791
6792/* initial stringtable size, must be prime and higher than DUK_UTIL_MIN_HASH_PRIME */
6793#define DUK_STRTAB_INITIAL_SIZE 17
6794
6795/* indicates a deleted string; any fixed non-NULL, non-hstring pointer works */
6796#define DUK_STRTAB_DELETED_MARKER(heap) ((duk_hstring *) heap)
6797
6798/* resizing parameters */
6799#define DUK_STRTAB_MIN_FREE_DIVISOR 4 /* load factor max 75% */
6800#define DUK_STRTAB_MIN_USED_DIVISOR 4 /* load factor min 25% */
6801#define DUK_STRTAB_GROW_ST_SIZE(n) ((n) + (n)) /* used entries + approx 100% -> reset load to 50% */
6802
6803#define DUK_STRTAB_U32_MAX_STRLEN 10 /* 4'294'967'295 */
6804#define DUK_STRTAB_HIGHEST_32BIT_PRIME 0xfffffffbUL
6805
6806/* probe sequence (open addressing) */
6807#define DUK_STRTAB_HASH_INITIAL(hash,h_size) ((hash) % (h_size))
6808#define DUK_STRTAB_HASH_PROBE_STEP(hash) DUK_UTIL_GET_HASH_PROBE_STEP((hash))
6809
6810/* fixed top level hashtable size (separate chaining) */
6811#define DUK_STRTAB_CHAIN_SIZE DUK_USE_STRTAB_CHAIN_SIZE
6812
6813/*
6814 * Built-in strings
6815 */
6816
6817/* heap string indices are autogenerated in duk_strings.h */
11fdf7f2
TL
6818#if defined(DUK_USE_ROM_STRINGS)
6819#define DUK_HEAP_GET_STRING(heap,idx) \
6820 ((duk_hstring *) DUK_LOSE_CONST(duk_rom_strings_stridx[(idx)]))
6821#else /* DUK_USE_ROM_STRINGS */
7c673cae
FG
6822#if defined(DUK_USE_HEAPPTR16)
6823#define DUK_HEAP_GET_STRING(heap,idx) \
6824 ((duk_hstring *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (heap)->strs16[(idx)]))
6825#else
6826#define DUK_HEAP_GET_STRING(heap,idx) \
6827 ((heap)->strs[(idx)])
6828#endif
11fdf7f2 6829#endif /* DUK_USE_ROM_STRINGS */
7c673cae
FG
6830
6831/*
6832 * Raw memory calls: relative to heap, but no GC interaction
6833 */
6834
6835#define DUK_ALLOC_RAW(heap,size) \
6836 ((heap)->alloc_func((heap)->heap_udata, (size)))
6837
6838#define DUK_REALLOC_RAW(heap,ptr,newsize) \
6839 ((heap)->realloc_func((heap)->heap_udata, (void *) (ptr), (newsize)))
6840
6841#define DUK_FREE_RAW(heap,ptr) \
6842 ((heap)->free_func((heap)->heap_udata, (void *) (ptr)))
6843
6844/*
6845 * Memory calls: relative to heap, GC interaction, but no error throwing.
6846 *
6847 * XXX: Currently a mark-and-sweep triggered by memory allocation will run
6848 * using the heap->heap_thread. This thread is also used for running
6849 * mark-and-sweep finalization; this is not ideal because it breaks the
6850 * isolation between multiple global environments.
6851 *
6852 * Notes:
6853 *
6854 * - DUK_FREE() is required to ignore NULL and any other possible return
6855 * value of a zero-sized alloc/realloc (same as ANSI C free()).
6856 *
6857 * - There is no DUK_REALLOC_ZEROED because we don't assume to know the
6858 * old size. Caller must zero the reallocated memory.
6859 *
6860 * - DUK_REALLOC_INDIRECT() must be used when a mark-and-sweep triggered
6861 * by an allocation failure might invalidate the original 'ptr', thus
6862 * causing a realloc retry to use an invalid pointer. Example: we're
6863 * reallocating the value stack and a finalizer resizes the same value
6864 * stack during mark-and-sweep. The indirect variant requests for the
6865 * current location of the pointer being reallocated using a callback
6866 * right before every realloc attempt; this circuitous approach is used
6867 * to avoid strict aliasing issues in a more straightforward indirect
6868 * pointer (void **) approach. Note: the pointer in the storage
6869 * location is read but is NOT updated; the caller must do that.
6870 */
6871
6872/* callback for indirect reallocs, request for current pointer */
6873typedef void *(*duk_mem_getptr)(duk_heap *heap, void *ud);
6874
6875#define DUK_ALLOC(heap,size) duk_heap_mem_alloc((heap), (size))
6876#define DUK_ALLOC_ZEROED(heap,size) duk_heap_mem_alloc_zeroed((heap), (size))
6877#define DUK_REALLOC(heap,ptr,newsize) duk_heap_mem_realloc((heap), (ptr), (newsize))
6878#define DUK_REALLOC_INDIRECT(heap,cb,ud,newsize) duk_heap_mem_realloc_indirect((heap), (cb), (ud), (newsize))
6879#define DUK_FREE(heap,ptr) duk_heap_mem_free((heap), (ptr))
6880
6881/*
6882 * Memory constants
6883 */
6884
6885#define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT 5 /* Retry allocation after mark-and-sweep for this
6886 * many times. A single mark-and-sweep round is
6887 * not guaranteed to free all unreferenced memory
6888 * because of finalization (in fact, ANY number of
6889 * rounds is strictly not enough).
6890 */
6891
6892#define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT 3 /* Starting from this round, use emergency mode
6893 * for mark-and-sweep.
6894 */
6895
6896/*
6897 * Debugger support
6898 */
6899
6900/* Maximum number of breakpoints. Only breakpoints that are set are
6901 * consulted so increasing this has no performance impact.
6902 */
6903#define DUK_HEAP_MAX_BREAKPOINTS 16
6904
6905/* Opcode interval for a Date-based status/peek rate limit check. Only
6906 * relevant when debugger is attached. Requesting a timestamp may be a
6907 * slow operation on some platforms so this shouldn't be too low. On the
6908 * other hand a high value makes Duktape react to a pause request slowly.
6909 */
6910#define DUK_HEAP_DBG_RATELIMIT_OPCODES 4000
6911
6912/* Milliseconds between status notify and transport peeks. */
6913#define DUK_HEAP_DBG_RATELIMIT_MILLISECS 200
6914
6915/* Step types */
6916#define DUK_STEP_TYPE_NONE 0
6917#define DUK_STEP_TYPE_INTO 1
6918#define DUK_STEP_TYPE_OVER 2
6919#define DUK_STEP_TYPE_OUT 3
6920
6921struct duk_breakpoint {
6922 duk_hstring *filename;
6923 duk_uint32_t line;
6924};
6925
6926#if defined(DUK_USE_DEBUGGER_SUPPORT)
6927#define DUK_HEAP_IS_DEBUGGER_ATTACHED(heap) ((heap)->dbg_read_cb != NULL)
6928#define DUK_HEAP_CLEAR_STEP_STATE(heap) do { \
6929 (heap)->dbg_step_type = DUK_STEP_TYPE_NONE; \
6930 (heap)->dbg_step_thread = NULL; \
6931 (heap)->dbg_step_csindex = 0; \
6932 (heap)->dbg_step_startline = 0; \
6933 } while (0)
6934#define DUK_HEAP_SET_PAUSED(heap) do { \
6935 (heap)->dbg_paused = 1; \
6936 (heap)->dbg_state_dirty = 1; \
6937 DUK_HEAP_CLEAR_STEP_STATE((heap)); \
6938 } while (0)
6939#define DUK_HEAP_CLEAR_PAUSED(heap) do { \
6940 (heap)->dbg_paused = 0; \
6941 (heap)->dbg_state_dirty = 1; \
6942 DUK_HEAP_CLEAR_STEP_STATE((heap)); \
6943 } while (0)
11fdf7f2 6944#define DUK_HEAP_IS_PAUSED(heap) ((heap)->dbg_paused)
7c673cae
FG
6945#endif /* DUK_USE_DEBUGGER_SUPPORT */
6946
6947/*
6948 * String cache should ideally be at duk_hthread level, but that would
6949 * cause string finalization to slow down relative to the number of
6950 * threads; string finalization must check the string cache for "weak"
6951 * references to the string being finalized to avoid dead pointers.
6952 *
6953 * Thus, string caches are now at the heap level now.
6954 */
6955
6956struct duk_strcache {
6957 duk_hstring *h;
6958 duk_uint32_t bidx;
6959 duk_uint32_t cidx;
6960};
6961
6962/*
6963 * Longjmp state, contains the information needed to perform a longjmp.
6964 * Longjmp related values are written to value1, value2, and iserror.
6965 */
6966
6967struct duk_ljstate {
6968 duk_jmpbuf *jmpbuf_ptr; /* current setjmp() catchpoint */
6969 duk_small_uint_t type; /* longjmp type */
6970 duk_bool_t iserror; /* isError flag for yield */
6971 duk_tval value1; /* 1st related value (type specific) */
6972 duk_tval value2; /* 2nd related value (type specific) */
6973};
6974
6975/*
6976 * Stringtable entry for fixed size stringtable
6977 */
6978
6979struct duk_strtab_entry {
6980#if defined(DUK_USE_HEAPPTR16)
6981 /* A 16-bit listlen makes sense with 16-bit heap pointers: there
6982 * won't be space for 64k strings anyway.
6983 */
6984 duk_uint16_t listlen; /* if 0, 'str16' used, if > 0, 'strlist16' used */
6985 union {
6986 duk_uint16_t strlist16;
6987 duk_uint16_t str16;
6988 } u;
6989#else
6990 duk_size_t listlen; /* if 0, 'str' used, if > 0, 'strlist' used */
6991 union {
6992 duk_hstring **strlist;
6993 duk_hstring *str;
6994 } u;
6995#endif
6996};
6997
6998/*
6999 * Main heap structure
7000 */
7001
7002struct duk_heap {
7003 duk_small_uint_t flags;
7004
7005 /* Allocator functions. */
7006 duk_alloc_function alloc_func;
7007 duk_realloc_function realloc_func;
7008 duk_free_function free_func;
7009
7010 /* Heap udata, used for allocator functions but also for other heap
7011 * level callbacks like pointer compression, etc.
7012 */
7013 void *heap_udata;
7014
7015 /* Precomputed pointers when using 16-bit heap pointer packing. */
7016#if defined(DUK_USE_HEAPPTR16)
7017 duk_uint16_t heapptr_null16;
7018 duk_uint16_t heapptr_deleted16;
7019#endif
7020
7021 /* Fatal error handling, called e.g. when a longjmp() is needed but
7022 * lj.jmpbuf_ptr is NULL. fatal_func must never return; it's not
7023 * declared as "noreturn" because doing that for typedefs is a bit
7024 * challenging portability-wise.
7025 */
7026 duk_fatal_function fatal_func;
7027
7028 /* allocated heap objects */
7029 duk_heaphdr *heap_allocated;
7030
7031 /* work list for objects whose refcounts are zero but which have not been
7032 * "finalized"; avoids recursive C calls when refcounts go to zero in a
7033 * chain of objects.
7034 */
7035#if defined(DUK_USE_REFERENCE_COUNTING)
7036 duk_heaphdr *refzero_list;
7037 duk_heaphdr *refzero_list_tail;
7038#endif
7039
7040#if defined(DUK_USE_MARK_AND_SWEEP)
7041 /* mark-and-sweep control */
7042#if defined(DUK_USE_VOLUNTARY_GC)
7043 duk_int_t mark_and_sweep_trigger_counter;
7044#endif
7045 duk_int_t mark_and_sweep_recursion_depth;
7046
7047 /* mark-and-sweep flags automatically active (used for critical sections) */
7048 duk_small_uint_t mark_and_sweep_base_flags;
7049
7050 /* work list for objects to be finalized (by mark-and-sweep) */
7051 duk_heaphdr *finalize_list;
7052#endif
7053
7054 /* longjmp state */
7055 duk_ljstate lj;
7056
7057 /* marker for detecting internal "double faults", see duk_error_throw.c */
7058 duk_bool_t handling_error;
7059
7060 /* heap thread, used internally and for finalization */
7061 duk_hthread *heap_thread;
7062
7063 /* current thread */
7064 duk_hthread *curr_thread; /* currently running thread */
7065
7066 /* heap level "stash" object (e.g., various reachability roots) */
7067 duk_hobject *heap_object;
7068
7069 /* duk_handle_call / duk_handle_safe_call recursion depth limiting */
7070 duk_int_t call_recursion_depth;
7071 duk_int_t call_recursion_limit;
7072
7073 /* mix-in value for computing string hashes; should be reasonably unpredictable */
7074 duk_uint32_t hash_seed;
7075
7076 /* rnd_state for duk_util_tinyrandom.c */
7077 duk_uint32_t rnd_state;
7078
7079 /* For manual debugging: instruction count based on executor and
7080 * interrupt counter book-keeping. Inspect debug logs to see how
7081 * they match up.
7082 */
7083#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
7084 duk_int_t inst_count_exec;
7085 duk_int_t inst_count_interrupt;
7086#endif
7087
7088 /* debugger */
7089
7090#if defined(DUK_USE_DEBUGGER_SUPPORT)
7091 /* callbacks and udata; dbg_read_cb != NULL is used to indicate attached state */
7092 duk_debug_read_function dbg_read_cb; /* required, NULL implies detached */
7093 duk_debug_write_function dbg_write_cb; /* required */
7094 duk_debug_peek_function dbg_peek_cb;
7095 duk_debug_read_flush_function dbg_read_flush_cb;
7096 duk_debug_write_flush_function dbg_write_flush_cb;
11fdf7f2 7097 duk_debug_request_function dbg_request_cb;
7c673cae
FG
7098 duk_debug_detached_function dbg_detached_cb;
7099 void *dbg_udata;
7100
7101 /* debugger state, only relevant when attached */
7102 duk_bool_t dbg_processing; /* currently processing messages or breakpoints: don't enter message processing recursively (e.g. no breakpoints when processing debugger eval) */
7103 duk_bool_t dbg_paused; /* currently paused: talk with debug client until step/resume */
7104 duk_bool_t dbg_state_dirty; /* resend state next time executor is about to run */
7105 duk_bool_t dbg_force_restart; /* force executor restart to recheck breakpoints; used to handle function returns (see GH-303) */
11fdf7f2 7106 duk_bool_t dbg_detaching; /* debugger detaching; used to avoid calling detach handler recursively */
7c673cae
FG
7107 duk_small_uint_t dbg_step_type; /* step type: none, step into, step over, step out */
7108 duk_hthread *dbg_step_thread; /* borrowed; NULL if no step state (NULLed in unwind) */
7109 duk_size_t dbg_step_csindex; /* callstack index */
7110 duk_uint32_t dbg_step_startline; /* starting line number */
7111 duk_breakpoint dbg_breakpoints[DUK_HEAP_MAX_BREAKPOINTS]; /* breakpoints: [0,breakpoint_count[ gc reachable */
7112 duk_small_uint_t dbg_breakpoint_count;
7113 duk_breakpoint *dbg_breakpoints_active[DUK_HEAP_MAX_BREAKPOINTS + 1]; /* currently active breakpoints: NULL term, borrowed pointers */
7114 /* XXX: make active breakpoints actual copies instead of pointers? */
7115
7116 /* These are for rate limiting Status notifications and transport peeking. */
7117 duk_uint32_t dbg_exec_counter; /* cumulative opcode execution count (overflows are OK) */
7118 duk_uint32_t dbg_last_counter; /* value of dbg_exec_counter when we last did a Date-based check */
7119 duk_double_t dbg_last_time; /* time when status/peek was last done (Date-based rate limit) */
11fdf7f2
TL
7120
7121 /* Used to support single-byte stream lookahead. */
7122 duk_bool_t dbg_have_next_byte;
7123 duk_uint8_t dbg_next_byte;
7c673cae
FG
7124#endif
7125
7126 /* string intern table (weak refs) */
7127#if defined(DUK_USE_STRTAB_PROBE)
7128#if defined(DUK_USE_HEAPPTR16)
7129 duk_uint16_t *strtable16;
7130#else
7131 duk_hstring **strtable;
7132#endif
7133 duk_uint32_t st_size; /* alloc size in elements */
7134 duk_uint32_t st_used; /* used elements (includes DELETED) */
7135#endif
7136
7137 /* XXX: static alloc is OK until separate chaining stringtable
7138 * resizing is implemented.
7139 */
7140#if defined(DUK_USE_STRTAB_CHAIN)
7141 duk_strtab_entry strtable[DUK_STRTAB_CHAIN_SIZE];
7142#endif
7143
7144 /* string access cache (codepoint offset -> byte offset) for fast string
7145 * character looping; 'weak' reference which needs special handling in GC.
7146 */
7147 duk_strcache strcache[DUK_HEAP_STRCACHE_SIZE];
7148
7149 /* built-in strings */
11fdf7f2
TL
7150#if defined(DUK_USE_ROM_STRINGS)
7151 /* No field needed when strings are in ROM. */
7152#else
7c673cae
FG
7153#if defined(DUK_USE_HEAPPTR16)
7154 duk_uint16_t strs16[DUK_HEAP_NUM_STRINGS];
7155#else
7156 duk_hstring *strs[DUK_HEAP_NUM_STRINGS];
7157#endif
11fdf7f2 7158#endif
7c673cae
FG
7159};
7160
7161/*
7162 * Prototypes
7163 */
7164
7165DUK_INTERNAL_DECL
7166duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
7167 duk_realloc_function realloc_func,
7168 duk_free_function free_func,
7169 void *heap_udata,
7170 duk_fatal_function fatal_func);
7171DUK_INTERNAL_DECL void duk_heap_free(duk_heap *heap);
7172DUK_INTERNAL_DECL void duk_free_hobject_inner(duk_heap *heap, duk_hobject *h);
7173DUK_INTERNAL_DECL void duk_free_hbuffer_inner(duk_heap *heap, duk_hbuffer *h);
7174DUK_INTERNAL_DECL void duk_free_hstring_inner(duk_heap *heap, duk_hstring *h);
7175DUK_INTERNAL_DECL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr);
7176
7177DUK_INTERNAL_DECL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr);
7178#if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_REFERENCE_COUNTING)
7179DUK_INTERNAL_DECL void duk_heap_remove_any_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr);
7180#endif
7181#if defined(DUK_USE_INTERRUPT_COUNTER)
7182DUK_INTERNAL_DECL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr);
7183#endif
7184
7185#if 0 /*unused*/
7186DUK_INTERNAL_DECL duk_hstring *duk_heap_string_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen);
7187#endif
7188DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen);
7189DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t len);
7190#if 0 /*unused*/
7191DUK_INTERNAL_DECL duk_hstring *duk_heap_string_lookup_u32(duk_heap *heap, duk_uint32_t val);
7192#endif
7193DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_u32(duk_heap *heap, duk_uint32_t val);
7194DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_u32_checked(duk_hthread *thr, duk_uint32_t val);
11fdf7f2 7195#if defined(DUK_USE_REFERENCE_COUNTING)
7c673cae 7196DUK_INTERNAL_DECL void duk_heap_string_remove(duk_heap *heap, duk_hstring *h);
11fdf7f2 7197#endif
7c673cae
FG
7198#if defined(DUK_USE_MARK_AND_SWEEP) && defined(DUK_USE_MS_STRINGTABLE_RESIZE)
7199DUK_INTERNAL_DECL void duk_heap_force_strtab_resize(duk_heap *heap);
7200#endif
7201DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap);
7202#if defined(DUK_USE_DEBUG)
7203DUK_INTERNAL void duk_heap_dump_strtab(duk_heap *heap);
7204#endif
7205
7206
7207DUK_INTERNAL_DECL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h);
7208DUK_INTERNAL_DECL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset);
7209
7210#if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS)
7211DUK_INTERNAL_DECL void *duk_default_alloc_function(void *udata, duk_size_t size);
7212DUK_INTERNAL_DECL void *duk_default_realloc_function(void *udata, void *ptr, duk_size_t newsize);
7213DUK_INTERNAL_DECL void duk_default_free_function(void *udata, void *ptr);
7214#endif
7215
7216DUK_INTERNAL_DECL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size);
7217DUK_INTERNAL_DECL void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size);
7218DUK_INTERNAL_DECL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize);
7219DUK_INTERNAL_DECL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize);
7220DUK_INTERNAL_DECL void duk_heap_mem_free(duk_heap *heap, void *ptr);
7221
7222#ifdef DUK_USE_REFERENCE_COUNTING
7223#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
7224DUK_INTERNAL_DECL void duk_tval_incref(duk_tval *tv);
7225#endif
7226#if 0 /* unused */
7227DUK_INTERNAL_DECL void duk_tval_incref_allownull(duk_tval *tv);
7228#endif
7229DUK_INTERNAL_DECL void duk_tval_decref(duk_hthread *thr, duk_tval *tv);
7230#if 0 /* unused */
7231DUK_INTERNAL_DECL void duk_tval_decref_allownull(duk_hthread *thr, duk_tval *tv);
7232#endif
7233#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
7234DUK_INTERNAL_DECL void duk_heaphdr_incref(duk_heaphdr *h);
7235#endif
7236#if 0 /* unused */
7237DUK_INTERNAL_DECL void duk_heaphdr_incref_allownull(duk_heaphdr *h);
7238#endif
7239DUK_INTERNAL_DECL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h);
7240DUK_INTERNAL_DECL void duk_heaphdr_decref_allownull(duk_hthread *thr, duk_heaphdr *h);
7241DUK_INTERNAL_DECL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h);
7242DUK_INTERNAL_DECL void duk_heaphdr_refcount_finalize(duk_hthread *thr, duk_heaphdr *hdr);
7243#else
7244/* no refcounting */
7245#endif
7246
7247#if defined(DUK_USE_MARK_AND_SWEEP)
7248DUK_INTERNAL_DECL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags);
7249#endif
7250
7251DUK_INTERNAL_DECL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len);
7252
7253#endif /* DUK_HEAP_H_INCLUDED */
7c673cae
FG
7254#ifndef DUK_DEBUGGER_H_INCLUDED
7255#define DUK_DEBUGGER_H_INCLUDED
7256
7257/* Debugger protocol version is defined in the public API header. */
7258
11fdf7f2
TL
7259/* Initial bytes for markers. */
7260#define DUK_DBG_IB_EOM 0x00
7261#define DUK_DBG_IB_REQUEST 0x01
7262#define DUK_DBG_IB_REPLY 0x02
7263#define DUK_DBG_IB_ERROR 0x03
7264#define DUK_DBG_IB_NOTIFY 0x04
7265
7266/* Other initial bytes. */
7267#define DUK_DBG_IB_INT4 0x10
7268#define DUK_DBG_IB_STR4 0x11
7269#define DUK_DBG_IB_STR2 0x12
7270#define DUK_DBG_IB_BUF4 0x13
7271#define DUK_DBG_IB_BUF2 0x14
7272#define DUK_DBG_IB_UNUSED 0x15
7273#define DUK_DBG_IB_UNDEFINED 0x16
7274#define DUK_DBG_IB_NULL 0x17
7275#define DUK_DBG_IB_TRUE 0x18
7276#define DUK_DBG_IB_FALSE 0x19
7277#define DUK_DBG_IB_NUMBER 0x1a
7278#define DUK_DBG_IB_OBJECT 0x1b
7279#define DUK_DBG_IB_POINTER 0x1c
7280#define DUK_DBG_IB_LIGHTFUNC 0x1d
7281#define DUK_DBG_IB_HEAPPTR 0x1e
7282/* The short string/integer initial bytes starting from 0x60 don't have
7283 * defines now.
7284 */
7285
7286/* Error codes. */
7287#define DUK_DBG_ERR_UNKNOWN 0x00
7288#define DUK_DBG_ERR_UNSUPPORTED 0x01
7289#define DUK_DBG_ERR_TOOMANY 0x02
7290#define DUK_DBG_ERR_NOTFOUND 0x03
7291#define DUK_DBG_ERR_APPLICATION 0x04
7292
7293/* Commands and notifys initiated by Duktape. */
7294#define DUK_DBG_CMD_STATUS 0x01
7295#define DUK_DBG_CMD_PRINT 0x02
7296#define DUK_DBG_CMD_ALERT 0x03
7297#define DUK_DBG_CMD_LOG 0x04
7298#define DUK_DBG_CMD_THROW 0x05
7299#define DUK_DBG_CMD_DETACHING 0x06
7300#define DUK_DBG_CMD_APPNOTIFY 0x07
7301
7302/* Commands initiated by debug client. */
7303#define DUK_DBG_CMD_BASICINFO 0x10
7304#define DUK_DBG_CMD_TRIGGERSTATUS 0x11
7305#define DUK_DBG_CMD_PAUSE 0x12
7306#define DUK_DBG_CMD_RESUME 0x13
7307#define DUK_DBG_CMD_STEPINTO 0x14
7308#define DUK_DBG_CMD_STEPOVER 0x15
7309#define DUK_DBG_CMD_STEPOUT 0x16
7310#define DUK_DBG_CMD_LISTBREAK 0x17
7311#define DUK_DBG_CMD_ADDBREAK 0x18
7312#define DUK_DBG_CMD_DELBREAK 0x19
7313#define DUK_DBG_CMD_GETVAR 0x1a
7314#define DUK_DBG_CMD_PUTVAR 0x1b
7315#define DUK_DBG_CMD_GETCALLSTACK 0x1c
7316#define DUK_DBG_CMD_GETLOCALS 0x1d
7317#define DUK_DBG_CMD_EVAL 0x1e
7318#define DUK_DBG_CMD_DETACH 0x1f
7319#define DUK_DBG_CMD_DUMPHEAP 0x20
7320#define DUK_DBG_CMD_GETBYTECODE 0x21
7321#define DUK_DBG_CMD_APPREQUEST 0x22
7322#define DUK_DBG_CMD_GETHEAPOBJINFO 0x23
7323#define DUK_DBG_CMD_GETOBJPROPDESC 0x24
7324#define DUK_DBG_CMD_GETOBJPROPDESCRANGE 0x25
7325
7326/* The low 8 bits map directly to duk_hobject.h DUK_PROPDESC_FLAG_xxx.
7327 * The remaining flags are specific to the debugger.
7328 */
7329#define DUK_DBG_PROPFLAG_INTERNAL (1 << 8)
7c673cae
FG
7330
7331#if defined(DUK_USE_DEBUGGER_SUPPORT)
7332DUK_INTERNAL_DECL void duk_debug_do_detach(duk_heap *heap);
7333
7334DUK_INTERNAL_DECL duk_bool_t duk_debug_read_peek(duk_hthread *thr);
7335DUK_INTERNAL_DECL void duk_debug_write_flush(duk_hthread *thr);
7336
7337DUK_INTERNAL_DECL void duk_debug_skip_bytes(duk_hthread *thr, duk_size_t length);
7338DUK_INTERNAL_DECL void duk_debug_skip_byte(duk_hthread *thr);
7339
7340DUK_INTERNAL_DECL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_size_t length);
7341DUK_INTERNAL_DECL duk_uint8_t duk_debug_read_byte(duk_hthread *thr);
7342DUK_INTERNAL_DECL duk_int32_t duk_debug_read_int(duk_hthread *thr);
7343DUK_INTERNAL_DECL duk_hstring *duk_debug_read_hstring(duk_hthread *thr);
7344/* XXX: exposed duk_debug_read_pointer */
7345/* XXX: exposed duk_debug_read_buffer */
7346/* XXX: exposed duk_debug_read_hbuffer */
11fdf7f2
TL
7347#if 0
7348DUK_INTERNAL_DECL duk_heaphdr *duk_debug_read_heapptr(duk_hthread *thr);
7349#endif
7350#if defined(DUK_USE_DEBUGGER_INSPECT)
7351DUK_INTERNAL_DECL duk_heaphdr *duk_debug_read_any_ptr(duk_hthread *thr);
7352#endif
7353DUK_INTERNAL_DECL duk_tval *duk_debug_read_tval(duk_hthread *thr);
7c673cae
FG
7354
7355DUK_INTERNAL_DECL void duk_debug_write_bytes(duk_hthread *thr, const duk_uint8_t *data, duk_size_t length);
7356DUK_INTERNAL_DECL void duk_debug_write_byte(duk_hthread *thr, duk_uint8_t x);
7357DUK_INTERNAL_DECL void duk_debug_write_unused(duk_hthread *thr);
7358DUK_INTERNAL_DECL void duk_debug_write_undefined(duk_hthread *thr);
11fdf7f2
TL
7359#if defined(DUK_USE_DEBUGGER_INSPECT)
7360DUK_INTERNAL_DECL void duk_debug_write_null(duk_hthread *thr);
7361#endif
7362DUK_INTERNAL_DECL void duk_debug_write_boolean(duk_hthread *thr, duk_uint_t val);
7c673cae
FG
7363DUK_INTERNAL_DECL void duk_debug_write_int(duk_hthread *thr, duk_int32_t x);
7364DUK_INTERNAL_DECL void duk_debug_write_uint(duk_hthread *thr, duk_uint32_t x);
7365DUK_INTERNAL_DECL void duk_debug_write_string(duk_hthread *thr, const char *data, duk_size_t length);
7366DUK_INTERNAL_DECL void duk_debug_write_cstring(duk_hthread *thr, const char *data);
7367DUK_INTERNAL_DECL void duk_debug_write_hstring(duk_hthread *thr, duk_hstring *h);
7368DUK_INTERNAL_DECL void duk_debug_write_buffer(duk_hthread *thr, const char *data, duk_size_t length);
7369DUK_INTERNAL_DECL void duk_debug_write_hbuffer(duk_hthread *thr, duk_hbuffer *h);
11fdf7f2
TL
7370DUK_INTERNAL_DECL void duk_debug_write_pointer(duk_hthread *thr, void *ptr);
7371#if defined(DUK_USE_DEBUGGER_DUMPHEAP) || defined(DUK_USE_DEBUGGER_INSPECT)
7c673cae
FG
7372DUK_INTERNAL_DECL void duk_debug_write_heapptr(duk_hthread *thr, duk_heaphdr *h);
7373#endif
7374DUK_INTERNAL_DECL void duk_debug_write_hobject(duk_hthread *thr, duk_hobject *obj);
7375DUK_INTERNAL_DECL void duk_debug_write_tval(duk_hthread *thr, duk_tval *tv);
7c673cae
FG
7376#if 0 /* unused */
7377DUK_INTERNAL_DECL void duk_debug_write_request(duk_hthread *thr, duk_small_uint_t command);
7378#endif
7379DUK_INTERNAL_DECL void duk_debug_write_reply(duk_hthread *thr);
7380DUK_INTERNAL_DECL void duk_debug_write_error_eom(duk_hthread *thr, duk_small_uint_t err_code, const char *msg);
7381DUK_INTERNAL_DECL void duk_debug_write_notify(duk_hthread *thr, duk_small_uint_t command);
7382DUK_INTERNAL_DECL void duk_debug_write_eom(duk_hthread *thr);
7383
11fdf7f2
TL
7384DUK_INTERNAL_DECL duk_uint_fast32_t duk_debug_curr_line(duk_hthread *thr);
7385DUK_INTERNAL_DECL void duk_debug_send_status(duk_hthread *thr);
7386#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY)
7387DUK_INTERNAL_DECL void duk_debug_send_throw(duk_hthread *thr, duk_bool_t fatal);
7388#endif
7c673cae 7389
11fdf7f2 7390DUK_INTERNAL_DECL void duk_debug_halt_execution(duk_hthread *thr, duk_bool_t use_prev_pc);
7c673cae
FG
7391DUK_INTERNAL_DECL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t no_block);
7392
7393DUK_INTERNAL_DECL duk_small_int_t duk_debug_add_breakpoint(duk_hthread *thr, duk_hstring *filename, duk_uint32_t line);
7394DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_uint_t breakpoint_index);
7395#endif
7396
7397#endif /* DUK_DEBUGGER_H_INCLUDED */
7c673cae
FG
7398/*
7399 * Debugging macros, DUK_DPRINT() and its variants in particular.
7400 *
7401 * DUK_DPRINT() allows formatted debug prints, and supports standard
7402 * and Duktape specific formatters. See duk_debug_vsnprintf.c for details.
7403 *
7404 * DUK_D(x), DUK_DD(x), and DUK_DDD(x) are used together with log macros
7405 * for technical reasons. They are concretely used to hide 'x' from the
7406 * compiler when the corresponding log level is disabled. This allows
7407 * clean builds on non-C99 compilers, at the cost of more verbose code.
7408 * Examples:
7409 *
7410 * DUK_D(DUK_DPRINT("foo"));
7411 * DUK_DD(DUK_DDPRINT("foo"));
7412 * DUK_DDD(DUK_DDDPRINT("foo"));
7413 *
7414 * This approach is preferable to the old "double parentheses" hack because
7415 * double parentheses make the C99 solution worse: __FILE__ and __LINE__ can
7416 * no longer be added transparently without going through globals, which
7417 * works poorly with threading.
7418 */
7419
7420#ifndef DUK_DEBUG_H_INCLUDED
7421#define DUK_DEBUG_H_INCLUDED
7422
7423#ifdef DUK_USE_DEBUG
7424
7425#if defined(DUK_USE_DPRINT)
7426#define DUK_D(x) x
7427#else
7428#define DUK_D(x) do { } while (0) /* omit */
7429#endif
7430
7431#if defined(DUK_USE_DDPRINT)
7432#define DUK_DD(x) x
7433#else
7434#define DUK_DD(x) do { } while (0) /* omit */
7435#endif
7436
7437#if defined(DUK_USE_DDDPRINT)
7438#define DUK_DDD(x) x
7439#else
7440#define DUK_DDD(x) do { } while (0) /* omit */
7441#endif
7442
7443/*
7444 * Exposed debug macros: debugging enabled
7445 */
7446
7447#define DUK_LEVEL_DEBUG 1
7448#define DUK_LEVEL_DDEBUG 2
7449#define DUK_LEVEL_DDDEBUG 3
7450
7451#ifdef DUK_USE_VARIADIC_MACROS
7452
7453/* Note: combining __FILE__, __LINE__, and __func__ into fmt would be
7454 * possible compile time, but waste some space with shared function names.
7455 */
7456#define DUK__DEBUG_LOG(lev,...) duk_debug_log((duk_small_int_t) (lev), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, DUK_FUNC_MACRO, __VA_ARGS__);
7457
7458#define DUK_DPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DEBUG, __VA_ARGS__)
7459
7460#ifdef DUK_USE_DDPRINT
7461#define DUK_DDPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DDEBUG, __VA_ARGS__)
7462#else
7463#define DUK_DDPRINT(...)
7464#endif
7465
7466#ifdef DUK_USE_DDDPRINT
7467#define DUK_DDDPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DDDEBUG, __VA_ARGS__)
7468#else
7469#define DUK_DDDPRINT(...)
7470#endif
7471
7472#else /* DUK_USE_VARIADIC_MACROS */
7473
7474#define DUK__DEBUG_STASH(lev) \
7475 (void) DUK_SNPRINTF(duk_debug_file_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FILE_MACRO), \
7476 duk_debug_file_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0; \
7477 (void) DUK_SNPRINTF(duk_debug_line_stash, DUK_DEBUG_STASH_SIZE, "%ld", (long) DUK_LINE_MACRO), \
7478 duk_debug_line_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0; \
7479 (void) DUK_SNPRINTF(duk_debug_func_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FUNC_MACRO), \
7480 duk_debug_func_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0; \
7481 (void) (duk_debug_level_stash = (lev))
7482
7483/* Without variadic macros resort to comma expression trickery to handle debug
7484 * prints. This generates a lot of harmless warnings. These hacks are not
7485 * needed normally because DUK_D() and friends will hide the entire debug log
7486 * statement from the compiler.
7487 */
7488
7489#ifdef DUK_USE_DPRINT
7490#define DUK_DPRINT DUK__DEBUG_STASH(DUK_LEVEL_DEBUG), (void) duk_debug_log /* args go here in parens */
7491#else
7492#define DUK_DPRINT 0 && /* args go here as a comma expression in parens */
7493#endif
7494
7495#ifdef DUK_USE_DDPRINT
7496#define DUK_DDPRINT DUK__DEBUG_STASH(DUK_LEVEL_DDEBUG), (void) duk_debug_log /* args go here in parens */
7497#else
7498#define DUK_DDPRINT 0 && /* args */
7499#endif
7500
7501#ifdef DUK_USE_DDDPRINT
7502#define DUK_DDDPRINT DUK__DEBUG_STASH(DUK_LEVEL_DDDEBUG), (void) duk_debug_log /* args go here in parens */
7503#else
7504#define DUK_DDDPRINT 0 && /* args */
7505#endif
7506
7507#endif /* DUK_USE_VARIADIC_MACROS */
7508
7509#else /* DUK_USE_DEBUG */
7510
7511/*
7512 * Exposed debug macros: debugging disabled
7513 */
7514
7515#define DUK_D(x) do { } while (0) /* omit */
7516#define DUK_DD(x) do { } while (0) /* omit */
7517#define DUK_DDD(x) do { } while (0) /* omit */
7518
7519#ifdef DUK_USE_VARIADIC_MACROS
7520
7521#define DUK_DPRINT(...)
7522#define DUK_DDPRINT(...)
7523#define DUK_DDDPRINT(...)
7524
7525#else /* DUK_USE_VARIADIC_MACROS */
7526
7527#define DUK_DPRINT 0 && /* args go here as a comma expression in parens */
7528#define DUK_DDPRINT 0 && /* args */
7529#define DUK_DDDPRINT 0 && /* args */
7530
7531#endif /* DUK_USE_VARIADIC_MACROS */
7532
7533#endif /* DUK_USE_DEBUG */
7534
7535/*
7536 * Structs
7537 */
7538
7539#ifdef DUK_USE_DEBUG
7540struct duk_fixedbuffer {
7541 duk_uint8_t *buffer;
7542 duk_size_t length;
7543 duk_size_t offset;
7544 duk_bool_t truncated;
7545};
7546#endif
7547
7548/*
7549 * Prototypes
7550 */
7551
7552#ifdef DUK_USE_DEBUG
7553DUK_INTERNAL_DECL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const char *format, va_list ap);
7554#if 0 /*unused*/
7555DUK_INTERNAL_DECL duk_int_t duk_debug_snprintf(char *str, duk_size_t size, const char *format, ...);
7556#endif
7557DUK_INTERNAL_DECL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_uint8_t *fptr, duk_size_t fptr_size);
7558
7559#ifdef DUK_USE_VARIADIC_MACROS
7560DUK_INTERNAL_DECL void duk_debug_log(duk_small_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...);
7561#else /* DUK_USE_VARIADIC_MACROS */
7562/* parameter passing, not thread safe */
7563#define DUK_DEBUG_STASH_SIZE 128
7564#if !defined(DUK_SINGLE_FILE)
7565DUK_INTERNAL_DECL char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE];
7566DUK_INTERNAL_DECL char duk_debug_line_stash[DUK_DEBUG_STASH_SIZE];
7567DUK_INTERNAL_DECL char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE];
7568DUK_INTERNAL_DECL duk_small_int_t duk_debug_level_stash;
7569#endif
7570DUK_INTERNAL_DECL void duk_debug_log(const char *fmt, ...);
7571#endif /* DUK_USE_VARIADIC_MACROS */
7572
11fdf7f2 7573DUK_INTERNAL_DECL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffer, duk_size_t length);
7c673cae
FG
7574DUK_INTERNAL_DECL void duk_fb_put_byte(duk_fixedbuffer *fb, duk_uint8_t x);
7575DUK_INTERNAL_DECL void duk_fb_put_cstring(duk_fixedbuffer *fb, const char *x);
7576DUK_INTERNAL_DECL void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...);
7577DUK_INTERNAL_DECL void duk_fb_put_funcptr(duk_fixedbuffer *fb, duk_uint8_t *fptr, duk_size_t fptr_size);
7578DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb);
7579
7580#endif /* DUK_USE_DEBUG */
7581
7582#endif /* DUK_DEBUG_H_INCLUDED */
7c673cae
FG
7583/*
7584 * Error handling macros, assertion macro, error codes.
7585 *
7586 * There are three level of 'errors':
7587 *
7588 * 1. Ordinary errors, relative to a thread, cause a longjmp, catchable.
7589 * 2. Fatal errors, relative to a heap, cause fatal handler to be called.
7590 * 3. Panic errors, unrelated to a heap and cause a process exit.
7591 *
7592 * Panics are used by the default fatal error handler and by debug code
7593 * such as assertions. By providing a proper fatal error handler, user
7594 * code can avoid panics in non-debug builds.
7595 */
7596
7597#ifndef DUK_ERROR_H_INCLUDED
7598#define DUK_ERROR_H_INCLUDED
7599
7600/*
7601 * Error codes: defined in duktape.h
7602 *
7603 * Error codes are used as a shorthand to throw exceptions from inside
7604 * the implementation. The appropriate Ecmascript object is constructed
7605 * based on the code. Ecmascript code throws objects directly. The error
7606 * codes are defined in the public API header because they are also used
7607 * by calling code.
7608 */
7609
7610/*
7611 * Normal error
7612 *
7613 * Normal error is thrown with a longjmp() through the current setjmp()
7614 * catchpoint record in the duk_heap. The 'curr_thread' of the duk_heap
7615 * identifies the throwing thread.
7616 *
11fdf7f2
TL
7617 * Error formatting is usually unnecessary. The error macros provide a
7618 * zero argument version (no formatting) and separate macros for small
7619 * argument counts. Variadic macros are not used to avoid portability
7620 * issues and avoid the need for stash-based workarounds when they're not
7621 * available. Vararg calls are avoided for non-formatted error calls
7622 * because vararg call sites are larger than normal, and there are a lot
7623 * of call sites with no formatting.
7624 *
7625 * Note that special formatting provided by debug macros is NOT available.
7c673cae
FG
7626 *
7627 * The _RAW variants allow the caller to specify file and line. This makes
7628 * it easier to write checked calls which want to use the call site of the
7629 * checked function, not the error macro call inside the checked function.
7c673cae
FG
7630 */
7631
11fdf7f2 7632#if defined(DUK_USE_VERBOSE_ERRORS)
7c673cae 7633
11fdf7f2
TL
7634/* Because there are quite many call sites, pack error code (require at most
7635 * 8-bit) into a single argument.
7636 */
7637#define DUK_ERROR(thr,err,msg) do { \
7638 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
7639 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
7640 duk_err_handle_error((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (msg)); \
7641 } while (0)
7642#define DUK_ERROR_RAW(thr,file,line,err,msg) do { \
7643 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
7644 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
7645 duk_err_handle_error((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (msg)); \
7646 } while (0)
7c673cae 7647
11fdf7f2
TL
7648#define DUK_ERROR_FMT1(thr,err,fmt,arg1) do { \
7649 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
7650 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
7651 duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1)); \
7652 } while (0)
7653#define DUK_ERROR_RAW_FMT1(thr,file,line,err,fmt,arg1) do { \
7654 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
7655 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
7656 duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1)); \
7657 } while (0)
7c673cae 7658
11fdf7f2
TL
7659#define DUK_ERROR_FMT2(thr,err,fmt,arg1,arg2) do { \
7660 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
7661 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
7662 duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2)); \
7663 } while (0)
7664#define DUK_ERROR_RAW_FMT2(thr,file,line,err,fmt,arg1,arg2) do { \
7665 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
7666 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
7667 duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2)); \
7668 } while (0)
7c673cae 7669
11fdf7f2
TL
7670#define DUK_ERROR_FMT3(thr,err,fmt,arg1,arg2,arg3) do { \
7671 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
7672 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
7673 duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3)); \
7674 } while (0)
7675#define DUK_ERROR_RAW_FMT3(thr,file,line,err,fmt,arg1,arg2,arg3) do { \
7676 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
7677 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
7678 duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3)); \
7679 } while (0)
7c673cae 7680
11fdf7f2
TL
7681#define DUK_ERROR_FMT4(thr,err,fmt,arg1,arg2,arg3,arg4) do { \
7682 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
7683 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
7684 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)); \
7685 } while (0)
7686#define DUK_ERROR_RAW_FMT4(thr,file,line,err,fmt,arg1,arg2,arg3,arg4) do { \
7687 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
7688 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
7689 duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3), (arg4)); \
7690 } while (0)
7c673cae
FG
7691
7692#else /* DUK_USE_VERBOSE_ERRORS */
7693
11fdf7f2
TL
7694#define DUK_ERROR(thr,err,msg) duk_err_handle_error((thr), (err))
7695#define DUK_ERROR_RAW(thr,file,line,err,msg) duk_err_handle_error((thr), (err))
7c673cae 7696
11fdf7f2
TL
7697#define DUK_ERROR_FMT1(thr,err,fmt,arg1) DUK_ERROR((thr),(err),(fmt))
7698#define DUK_ERROR_RAW_FMT1(thr,file,line,err,fmt,arg1) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt))
7c673cae 7699
11fdf7f2
TL
7700#define DUK_ERROR_FMT2(thr,err,fmt,arg1,arg2) DUK_ERROR((thr),(err),(fmt))
7701#define DUK_ERROR_RAW_FMT2(thr,file,line,err,fmt,arg1,arg2) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt))
7c673cae 7702
11fdf7f2
TL
7703#define DUK_ERROR_FMT3(thr,err,fmt,arg1,arg2,arg3) DUK_ERROR((thr),(err),(fmt))
7704#define DUK_ERROR_RAW_FMT3(thr,file,line,err,fmt,arg1,arg2,arg3) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt))
7c673cae 7705
11fdf7f2
TL
7706#define DUK_ERROR_FMT4(thr,err,fmt,arg1,arg2,arg3,arg4) DUK_ERROR((thr),(err),(fmt))
7707#define DUK_ERROR_RAW_FMT4(thr,file,line,err,fmt,arg1,arg2,arg3,arg4) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt))
7c673cae
FG
7708
7709#endif /* DUK_USE_VERBOSE_ERRORS */
7710
7711/*
7712 * Fatal error
7713 *
7714 * There are no fatal error macros at the moment. There are so few call
7715 * sites that the fatal error handler is called directly.
7716 */
7717
7718/*
7719 * Panic error
7720 *
7721 * Panic errors are not relative to either a heap or a thread, and cause
7722 * DUK_PANIC() macro to be invoked. Unless a user provides DUK_USE_PANIC_HANDLER,
7723 * DUK_PANIC() calls a helper which prints out the error and causes a process
7724 * exit.
7725 *
7726 * The user can override the macro to provide custom handling. A macro is
7727 * used to allow the user to have inline panic handling if desired (without
7728 * causing a potentially risky function call).
7729 *
7730 * Panics are only used in debug code such as assertions, and by the default
7731 * fatal error handler.
7732 */
7733
7734#if defined(DUK_USE_PANIC_HANDLER)
7735/* already defined, good */
7736#define DUK_PANIC(code,msg) DUK_USE_PANIC_HANDLER((code),(msg))
7737#else
7738#define DUK_PANIC(code,msg) duk_default_panic_handler((code),(msg))
7739#endif /* DUK_USE_PANIC_HANDLER */
7740
7741/*
7742 * Assert macro: failure causes panic.
7743 */
7744
11fdf7f2 7745#if defined(DUK_USE_ASSERTIONS)
7c673cae
FG
7746
7747/* the message should be a compile time constant without formatting (less risk);
7748 * we don't care about assertion text size because they're not used in production
7749 * builds.
7750 */
7751#define DUK_ASSERT(x) do { \
7752 if (!(x)) { \
7753 DUK_PANIC(DUK_ERR_ASSERTION_ERROR, \
7754 "assertion failed: " #x \
7755 " (" DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO) ")"); \
7756 } \
7757 } while (0)
7758
7759/* Assertion compatible inside a comma expression, evaluates to void.
7760 * Currently not compatible with DUK_USE_PANIC_HANDLER() which may have
7761 * a statement block.
7762 */
7763#if defined(DUK_USE_PANIC_HANDLER)
7764/* XXX: resolve macro definition issue or call through a helper function? */
7765#define DUK_ASSERT_EXPR(x) ((void) 0)
7766#else
7767#define DUK_ASSERT_EXPR(x) \
7768 ((void) ((x) ? 0 : (DUK_PANIC(DUK_ERR_ASSERTION_ERROR, \
7769 "assertion failed: " #x \
7770 " (" DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO) ")"), 0)))
7771#endif
7772
7773#else /* DUK_USE_ASSERTIONS */
7774
7775#define DUK_ASSERT(x) do { /* assertion omitted */ } while (0)
7776
7777#define DUK_ASSERT_EXPR(x) ((void) 0)
7778
7779#endif /* DUK_USE_ASSERTIONS */
7780
7781/* this variant is used when an assert would generate a compile warning by
7782 * being always true (e.g. >= 0 comparison for an unsigned value
7783 */
7784#define DUK_ASSERT_DISABLE(x) do { /* assertion disabled */ } while (0)
7785
7786/*
7787 * Assertion helpers
7788 */
7789
7790#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING)
7791#define DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(h) do { \
7792 DUK_ASSERT((h) == NULL || DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) (h)) > 0); \
7793 } while (0)
7794#define DUK_ASSERT_REFCOUNT_NONZERO_TVAL(tv) do { \
7795 if ((tv) != NULL && DUK_TVAL_IS_HEAP_ALLOCATED((tv))) { \
7796 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(DUK_TVAL_GET_HEAPHDR((tv))) > 0); \
7797 } \
7798 } while (0)
7799#else
7800#define DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(h) /* no refcount check */
7801#define DUK_ASSERT_REFCOUNT_NONZERO_TVAL(tv) /* no refcount check */
7802#endif
7803
7804#define DUK_ASSERT_TOP(ctx,n) DUK_ASSERT((duk_idx_t) duk_get_top((ctx)) == (duk_idx_t) (n))
7805
7806#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_PACKED_TVAL)
7807#define DUK_ASSERT_DOUBLE_IS_NORMALIZED(dval) do { \
7808 duk_double_union duk__assert_tmp_du; \
7809 duk__assert_tmp_du.d = (dval); \
7810 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&duk__assert_tmp_du)); \
7811 } while (0)
7812#else
7813#define DUK_ASSERT_DOUBLE_IS_NORMALIZED(dval) /* nop */
7814#endif
7815
7816/*
7817 * Helper for valstack space
7818 *
7819 * Caller of DUK_ASSERT_VALSTACK_SPACE() estimates the number of free stack entries
7820 * required for its own use, and any child calls which are not (a) Duktape API calls
7821 * or (b) Duktape calls which involve extending the valstack (e.g. getter call).
7822 */
7823
7824#define DUK_VALSTACK_ASSERT_EXTRA 5 /* this is added to checks to allow for Duktape
7825 * API calls in addition to function's own use
7826 */
7827#if defined(DUK_USE_ASSERTIONS)
7828#define DUK_ASSERT_VALSTACK_SPACE(thr,n) do { \
7829 DUK_ASSERT((thr) != NULL); \
7830 DUK_ASSERT((thr)->valstack_end - (thr)->valstack_top >= (n) + DUK_VALSTACK_ASSERT_EXTRA); \
7831 } while (0)
7832#else
7833#define DUK_ASSERT_VALSTACK_SPACE(thr,n) /* no valstack space check */
7834#endif
7835
11fdf7f2
TL
7836/*
7837 * Error throwing helpers
7838 *
7839 * The goal is to provide verbose and configurable error messages. Call
7840 * sites should be clean in source code and compile to a small footprint.
7841 * Small footprint is also useful for performance because small cold paths
7842 * reduce code cache pressure. Adding macros here only makes sense if there
7843 * are enough call sites to get concrete benefits.
7844 */
7845
7846#if defined(DUK_USE_VERBOSE_ERRORS)
7847/* Verbose errors with key/value summaries (non-paranoid) or without key/value
7848 * summaries (paranoid, for some security sensitive environments), the paranoid
7849 * vs. non-paranoid distinction affects only a few specific errors.
7850 */
7851#if defined(DUK_USE_PARANOID_ERRORS)
7852#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,index,expectname,lowmemstr) do { \
7853 duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (index), (expectname)); \
7854 } while (0)
7855#else /* DUK_USE_PARANOID_ERRORS */
7856#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,index,expectname,lowmemstr) do { \
7857 duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (index), (expectname)); \
7858 } while (0)
7859#endif /* DUK_USE_PARANOID_ERRORS */
7860
7861#define DUK_ERROR_UNIMPLEMENTED(thr,msg) do { \
7862 DUK_ERROR((thr), DUK_ERR_UNIMPLEMENTED_ERROR, (msg)); \
7863 } while (0)
7864#define DUK_ERROR_UNIMPLEMENTED_DEFMSG(thr) do { \
7865 duk_err_unimplemented_defmsg((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
7866 } while (0)
7867#define DUK_ERROR_UNSUPPORTED(thr,msg) do { \
7868 DUK_ERROR((thr), DUK_ERR_UNSUPPORTED_ERROR, (msg)); \
7869 } while (0)
7870#if !defined(DUK_USE_BYTECODE_DUMP_SUPPORT)
7871#define DUK_ERROR_UNSUPPORTED_DEFMSG(thr) do { \
7872 duk_err_unsupported_defmsg((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
7873 } while (0)
7874#endif
7875#define DUK_ERROR_INTERNAL(thr,msg) do { \
7876 duk_err_internal((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
7877 } while (0)
7878#define DUK_ERROR_INTERNAL_DEFMSG(thr) do { \
7879 duk_err_internal_defmsg((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
7880 } while (0)
7881#define DUK_ERROR_ALLOC(thr,msg) do { \
7882 duk_err_alloc((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
7883 } while (0)
7884#define DUK_ERROR_ALLOC_DEFMSG(thr) do { \
7885 DUK_ERROR_ALLOC((thr), DUK_STR_ALLOC_FAILED); \
7886 } while (0)
7887/* DUK_ERR_ASSERTION_ERROR: no macros needed */
7888#define DUK_ERROR_API_INDEX(thr,index) do { \
7889 duk_err_api_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (index)); \
7890 } while (0)
7891#define DUK_ERROR_API(thr,msg) do { \
7892 duk_err_api((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
7893 } while (0)
7894/* DUK_ERR_UNCAUGHT_ERROR: no macros needed */
7895/* DUK_ERR_ERROR: no macros needed */
7896/* DUK_ERR_EVAL: no macros needed */
7897#define DUK_ERROR_RANGE(thr,msg) do { \
7898 duk_err_range((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
7899 } while (0)
7900/* DUK_ERR_REFERENCE_ERROR: no macros needed */
7901#define DUK_ERROR_SYNTAX(thr,msg) do { \
7902 DUK_ERROR((thr), DUK_ERR_SYNTAX_ERROR, (msg)); \
7903 } while (0)
7904#define DUK_ERROR_TYPE(thr,msg) do { \
7905 DUK_ERROR((thr), DUK_ERR_TYPE_ERROR, (msg)); \
7906 } while (0)
7907/* DUK_ERR_URI_ERROR: no macros needed */
7908#else /* DUK_USE_VERBOSE_ERRORS */
7909/* Non-verbose errors for low memory targets: no file, line, or message. */
7910
7911#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,index,expectname,lowmemstr) do { \
7912 duk_err_type((thr)); \
7913 } while (0)
7914
7915#define DUK_ERROR_UNIMPLEMENTED(thr,msg) do { \
7916 duk_err_unimplemented((thr)); \
7917 } while (0)
7918#define DUK_ERROR_UNIMPLEMENTED_DEFMSG(thr) do { \
7919 duk_err_unimplemented((thr)); \
7920 } while (0)
7921#define DUK_ERROR_UNSUPPORTED(thr,msg) do { \
7922 duk_err_unsupported((thr)); \
7923 } while (0)
7924#define DUK_ERROR_UNSUPPORTED_DEFMSG(thr) do { \
7925 duk_err_unsupported((thr)); \
7926 } while (0)
7927#define DUK_ERROR_INTERNAL(thr,msg) do { \
7928 duk_err_internal((thr)); \
7929 } while (0)
7930#define DUK_ERROR_INTERNAL_DEFMSG(thr) do { \
7931 duk_err_internal((thr)); \
7932 } while (0)
7933#define DUK_ERROR_ALLOC(thr,msg) do { \
7934 duk_err_alloc((thr)); \
7935 } while (0)
7936#define DUK_ERROR_ALLOC_DEFMSG(thr) do { \
7937 duk_err_alloc((thr)); \
7938 } while (0)
7939#define DUK_ERROR_API_INDEX(thr,index) do { \
7940 duk_err_api((thr)); \
7941 } while (0)
7942#define DUK_ERROR_API(thr,msg) do { \
7943 duk_err_api((thr)); \
7944 } while (0)
7945#define DUK_ERROR_RANGE(thr,msg) do { \
7946 duk_err_range((thr)); \
7947 } while (0)
7948#define DUK_ERROR_SYNTAX(thr,msg) do { \
7949 duk_err_syntax((thr)); \
7950 } while (0)
7951#define DUK_ERROR_TYPE(thr,msg) do { \
7952 duk_err_type((thr)); \
7953 } while (0)
7954#endif /* DUK_USE_VERBOSE_ERRORS */
7955
7c673cae
FG
7956/*
7957 * Prototypes
7958 */
7959
11fdf7f2
TL
7960#if defined(DUK_USE_VERBOSE_ERRORS)
7961DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *msg));
7962DUK_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, ...));
7c673cae 7963#else /* DUK_USE_VERBOSE_ERRORS */
7c673cae 7964DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code));
7c673cae
FG
7965#endif /* DUK_USE_VERBOSE_ERRORS */
7966
11fdf7f2 7967#if defined(DUK_USE_VERBOSE_ERRORS)
7c673cae
FG
7968DUK_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));
7969#else
7970DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code));
7971#endif
7972
7973DUK_NORETURN(DUK_INTERNAL_DECL void duk_error_throw_from_negative_rc(duk_hthread *thr, duk_ret_t rc));
7974
7975#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
7976DUK_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);
7977#endif
7978#if defined(DUK_USE_AUGMENT_ERROR_THROW)
7979DUK_INTERNAL_DECL void duk_err_augment_error_throw(duk_hthread *thr);
7980#endif
7981
11fdf7f2
TL
7982#if defined(DUK_USE_VERBOSE_ERRORS)
7983#if defined(DUK_USE_PARANOID_ERRORS)
7984DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index, const char *expect_name));
7985#else
7986DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index, const char *expect_name));
7987#endif
7988DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index));
7989DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
7990DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
7991DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_unimplemented_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber));
7992#if !defined(DUK_USE_BYTECODE_DUMP_SUPPORT)
7993DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_unsupported_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber));
7994#endif
7995DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_internal_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber));
7996DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
7997DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_alloc(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
7998#else /* DUK_VERBOSE_ERRORS */
7999DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range(duk_hthread *thr));
8000DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_syntax(duk_hthread *thr));
8001DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type(duk_hthread *thr));
8002DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api(duk_hthread *thr));
8003DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_unimplemented(duk_hthread *thr));
8004DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_unsupported(duk_hthread *thr));
8005DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_internal(duk_hthread *thr));
8006DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_alloc(duk_hthread *thr));
8007#endif /* DUK_VERBOSE_ERRORS */
8008
7c673cae
FG
8009DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_longjmp(duk_hthread *thr));
8010
8011DUK_NORETURN(DUK_INTERNAL_DECL void duk_default_fatal_handler(duk_context *ctx, duk_errcode_t code, const char *msg));
8012
8013#if !defined(DUK_USE_PANIC_HANDLER)
8014DUK_NORETURN(DUK_INTERNAL_DECL void duk_default_panic_handler(duk_errcode_t code, const char *msg));
8015#endif
8016
8017DUK_INTERNAL_DECL void duk_err_setup_heap_ljstate(duk_hthread *thr, duk_small_int_t lj_type);
8018
8019DUK_INTERNAL_DECL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, duk_errcode_t err_code);
8020
8021#endif /* DUK_ERROR_H_INCLUDED */
7c673cae
FG
8022/*
8023 * Unicode helpers
8024 */
8025
8026#ifndef DUK_UNICODE_H_INCLUDED
8027#define DUK_UNICODE_H_INCLUDED
8028
8029/*
8030 * UTF-8 / XUTF-8 / CESU-8 constants
8031 */
8032
8033#define DUK_UNICODE_MAX_XUTF8_LENGTH 7 /* up to 36 bit codepoints */
8034#define DUK_UNICODE_MAX_XUTF8_BMP_LENGTH 3 /* all codepoints up to U+FFFF */
8035#define DUK_UNICODE_MAX_CESU8_LENGTH 6 /* all codepoints up to U+10FFFF */
8036#define DUK_UNICODE_MAX_CESU8_BMP_LENGTH 3 /* all codepoints up to U+FFFF */
8037
8038/*
8039 * Useful Unicode codepoints
8040 *
8041 * Integer constants must be signed to avoid unexpected coercions
8042 * in comparisons.
8043 */
8044
8045#define DUK_UNICODE_CP_ZWNJ 0x200cL /* zero-width non-joiner */
8046#define DUK_UNICODE_CP_ZWJ 0x200dL /* zero-width joiner */
8047#define DUK_UNICODE_CP_REPLACEMENT_CHARACTER 0xfffdL /* http://en.wikipedia.org/wiki/Replacement_character#Replacement_character */
8048
8049/*
8050 * ASCII character constants
8051 *
8052 * C character literals like 'x' have a platform specific value and do
8053 * not match ASCII (UTF-8) values on e.g. EBCDIC platforms. So, use
8054 * these (admittedly awkward) constants instead. These constants must
8055 * also have signed values to avoid unexpected coercions in comparisons.
8056 *
8057 * http://en.wikipedia.org/wiki/ASCII
8058 */
8059
8060#define DUK_ASC_NUL 0x00
8061#define DUK_ASC_SOH 0x01
8062#define DUK_ASC_STX 0x02
8063#define DUK_ASC_ETX 0x03
8064#define DUK_ASC_EOT 0x04
8065#define DUK_ASC_ENQ 0x05
8066#define DUK_ASC_ACK 0x06
8067#define DUK_ASC_BEL 0x07
8068#define DUK_ASC_BS 0x08
8069#define DUK_ASC_HT 0x09
8070#define DUK_ASC_LF 0x0a
8071#define DUK_ASC_VT 0x0b
8072#define DUK_ASC_FF 0x0c
8073#define DUK_ASC_CR 0x0d
8074#define DUK_ASC_SO 0x0e
8075#define DUK_ASC_SI 0x0f
8076#define DUK_ASC_DLE 0x10
8077#define DUK_ASC_DC1 0x11
8078#define DUK_ASC_DC2 0x12
8079#define DUK_ASC_DC3 0x13
8080#define DUK_ASC_DC4 0x14
8081#define DUK_ASC_NAK 0x15
8082#define DUK_ASC_SYN 0x16
8083#define DUK_ASC_ETB 0x17
8084#define DUK_ASC_CAN 0x18
8085#define DUK_ASC_EM 0x19
8086#define DUK_ASC_SUB 0x1a
8087#define DUK_ASC_ESC 0x1b
8088#define DUK_ASC_FS 0x1c
8089#define DUK_ASC_GS 0x1d
8090#define DUK_ASC_RS 0x1e
8091#define DUK_ASC_US 0x1f
8092#define DUK_ASC_SPACE 0x20
8093#define DUK_ASC_EXCLAMATION 0x21
8094#define DUK_ASC_DOUBLEQUOTE 0x22
8095#define DUK_ASC_HASH 0x23
8096#define DUK_ASC_DOLLAR 0x24
8097#define DUK_ASC_PERCENT 0x25
8098#define DUK_ASC_AMP 0x26
8099#define DUK_ASC_SINGLEQUOTE 0x27
8100#define DUK_ASC_LPAREN 0x28
8101#define DUK_ASC_RPAREN 0x29
8102#define DUK_ASC_STAR 0x2a
8103#define DUK_ASC_PLUS 0x2b
8104#define DUK_ASC_COMMA 0x2c
8105#define DUK_ASC_MINUS 0x2d
8106#define DUK_ASC_PERIOD 0x2e
8107#define DUK_ASC_SLASH 0x2f
8108#define DUK_ASC_0 0x30
8109#define DUK_ASC_1 0x31
8110#define DUK_ASC_2 0x32
8111#define DUK_ASC_3 0x33
8112#define DUK_ASC_4 0x34
8113#define DUK_ASC_5 0x35
8114#define DUK_ASC_6 0x36
8115#define DUK_ASC_7 0x37
8116#define DUK_ASC_8 0x38
8117#define DUK_ASC_9 0x39
8118#define DUK_ASC_COLON 0x3a
8119#define DUK_ASC_SEMICOLON 0x3b
8120#define DUK_ASC_LANGLE 0x3c
8121#define DUK_ASC_EQUALS 0x3d
8122#define DUK_ASC_RANGLE 0x3e
8123#define DUK_ASC_QUESTION 0x3f
8124#define DUK_ASC_ATSIGN 0x40
8125#define DUK_ASC_UC_A 0x41
8126#define DUK_ASC_UC_B 0x42
8127#define DUK_ASC_UC_C 0x43
8128#define DUK_ASC_UC_D 0x44
8129#define DUK_ASC_UC_E 0x45
8130#define DUK_ASC_UC_F 0x46
8131#define DUK_ASC_UC_G 0x47
8132#define DUK_ASC_UC_H 0x48
8133#define DUK_ASC_UC_I 0x49
8134#define DUK_ASC_UC_J 0x4a
8135#define DUK_ASC_UC_K 0x4b
8136#define DUK_ASC_UC_L 0x4c
8137#define DUK_ASC_UC_M 0x4d
8138#define DUK_ASC_UC_N 0x4e
8139#define DUK_ASC_UC_O 0x4f
8140#define DUK_ASC_UC_P 0x50
8141#define DUK_ASC_UC_Q 0x51
8142#define DUK_ASC_UC_R 0x52
8143#define DUK_ASC_UC_S 0x53
8144#define DUK_ASC_UC_T 0x54
8145#define DUK_ASC_UC_U 0x55
8146#define DUK_ASC_UC_V 0x56
8147#define DUK_ASC_UC_W 0x57
8148#define DUK_ASC_UC_X 0x58
8149#define DUK_ASC_UC_Y 0x59
8150#define DUK_ASC_UC_Z 0x5a
8151#define DUK_ASC_LBRACKET 0x5b
8152#define DUK_ASC_BACKSLASH 0x5c
8153#define DUK_ASC_RBRACKET 0x5d
8154#define DUK_ASC_CARET 0x5e
8155#define DUK_ASC_UNDERSCORE 0x5f
8156#define DUK_ASC_GRAVE 0x60
8157#define DUK_ASC_LC_A 0x61
8158#define DUK_ASC_LC_B 0x62
8159#define DUK_ASC_LC_C 0x63
8160#define DUK_ASC_LC_D 0x64
8161#define DUK_ASC_LC_E 0x65
8162#define DUK_ASC_LC_F 0x66
8163#define DUK_ASC_LC_G 0x67
8164#define DUK_ASC_LC_H 0x68
8165#define DUK_ASC_LC_I 0x69
8166#define DUK_ASC_LC_J 0x6a
8167#define DUK_ASC_LC_K 0x6b
8168#define DUK_ASC_LC_L 0x6c
8169#define DUK_ASC_LC_M 0x6d
8170#define DUK_ASC_LC_N 0x6e
8171#define DUK_ASC_LC_O 0x6f
8172#define DUK_ASC_LC_P 0x70
8173#define DUK_ASC_LC_Q 0x71
8174#define DUK_ASC_LC_R 0x72
8175#define DUK_ASC_LC_S 0x73
8176#define DUK_ASC_LC_T 0x74
8177#define DUK_ASC_LC_U 0x75
8178#define DUK_ASC_LC_V 0x76
8179#define DUK_ASC_LC_W 0x77
8180#define DUK_ASC_LC_X 0x78
8181#define DUK_ASC_LC_Y 0x79
8182#define DUK_ASC_LC_Z 0x7a
8183#define DUK_ASC_LCURLY 0x7b
8184#define DUK_ASC_PIPE 0x7c
8185#define DUK_ASC_RCURLY 0x7d
8186#define DUK_ASC_TILDE 0x7e
8187#define DUK_ASC_DEL 0x7f
8188
8189/*
8190 * Unicode tables
8191 */
8192
8193#ifdef DUK_USE_SOURCE_NONBMP
8194/*
8195 * Automatically generated by extract_chars.py, do not edit!
8196 */
8197
8198extern const duk_uint8_t duk_unicode_ids_noa[791];
8199#else
8200/*
8201 * Automatically generated by extract_chars.py, do not edit!
8202 */
8203
8204extern const duk_uint8_t duk_unicode_ids_noabmp[611];
8205#endif
8206
8207#ifdef DUK_USE_SOURCE_NONBMP
8208/*
8209 * Automatically generated by extract_chars.py, do not edit!
8210 */
8211
8212extern const duk_uint8_t duk_unicode_ids_m_let_noa[42];
8213#else
8214/*
8215 * Automatically generated by extract_chars.py, do not edit!
8216 */
8217
8218extern const duk_uint8_t duk_unicode_ids_m_let_noabmp[24];
8219#endif
8220
8221#ifdef DUK_USE_SOURCE_NONBMP
8222/*
8223 * Automatically generated by extract_chars.py, do not edit!
8224 */
8225
8226extern const duk_uint8_t duk_unicode_idp_m_ids_noa[397];
8227#else
8228/*
8229 * Automatically generated by extract_chars.py, do not edit!
8230 */
8231
8232extern const duk_uint8_t duk_unicode_idp_m_ids_noabmp[348];
8233#endif
8234
8235/*
8236 * Automatically generated by extract_caseconv.py, do not edit!
8237 */
8238
8239extern const duk_uint8_t duk_unicode_caseconv_uc[1288];
8240extern const duk_uint8_t duk_unicode_caseconv_lc[616];
8241
11fdf7f2
TL
8242#if defined(DUK_USE_REGEXP_CANON_WORKAROUND)
8243/*
8244 * Automatically generated by extract_caseconv.py, do not edit!
8245 */
8246
8247extern const duk_uint16_t duk_unicode_re_canon_lookup[65536];
8248#endif
8249
7c673cae
FG
8250/*
8251 * Extern
8252 */
8253
8254/* duk_unicode_support.c */
8255#if !defined(DUK_SINGLE_FILE)
11fdf7f2
TL
8256DUK_INTERNAL_DECL const duk_uint8_t duk_unicode_xutf8_markers[7];
8257DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_digit[2];
8258DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_white[22];
8259DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_wordchar[8];
8260DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_not_digit[4];
8261DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_not_white[24];
8262DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_not_wordchar[10];
8263DUK_INTERNAL_DECL const duk_int8_t duk_is_idchar_tab[128];
7c673cae
FG
8264#endif /* !DUK_SINGLE_FILE */
8265
8266/*
8267 * Prototypes
8268 */
8269
8270DUK_INTERNAL_DECL duk_small_int_t duk_unicode_get_xutf8_length(duk_ucodepoint_t cp);
8271#if defined(DUK_USE_ASSERTIONS)
8272DUK_INTERNAL_DECL duk_small_int_t duk_unicode_get_cesu8_length(duk_ucodepoint_t cp);
8273#endif
8274DUK_INTERNAL_DECL duk_small_int_t duk_unicode_encode_xutf8(duk_ucodepoint_t cp, duk_uint8_t *out);
8275DUK_INTERNAL_DECL duk_small_int_t duk_unicode_encode_cesu8(duk_ucodepoint_t cp, duk_uint8_t *out);
8276DUK_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);
8277DUK_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);
8278DUK_INTERNAL_DECL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen);
8279DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_whitespace(duk_codepoint_t cp);
8280DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_line_terminator(duk_codepoint_t cp);
8281DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_t cp);
8282DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp);
8283DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp);
8284DUK_INTERNAL_DECL void duk_unicode_case_convert_string(duk_hthread *thr, duk_bool_t uppercase);
8285DUK_INTERNAL_DECL duk_codepoint_t duk_unicode_re_canonicalize_char(duk_hthread *thr, duk_codepoint_t cp);
8286DUK_INTERNAL_DECL duk_small_int_t duk_unicode_re_is_wordchar(duk_codepoint_t cp);
8287
8288#endif /* DUK_UNICODE_H_INCLUDED */
7c673cae
FG
8289/*
8290 * Defines for JSON, especially duk_bi_json.c.
8291 */
8292
8293#ifndef DUK_JSON_H_INCLUDED
8294#define DUK_JSON_H_INCLUDED
8295
8296/* Encoding/decoding flags */
8297#define DUK_JSON_FLAG_ASCII_ONLY (1 << 0) /* escape any non-ASCII characters */
8298#define DUK_JSON_FLAG_AVOID_KEY_QUOTES (1 << 1) /* avoid key quotes when key is an ASCII Identifier */
8299#define DUK_JSON_FLAG_EXT_CUSTOM (1 << 2) /* extended types: custom encoding */
8300#define DUK_JSON_FLAG_EXT_COMPATIBLE (1 << 3) /* extended types: compatible encoding */
8301
8302/* How much stack to require on entry to object/array encode */
8303#define DUK_JSON_ENC_REQSTACK 32
8304
8305/* How much stack to require on entry to object/array decode */
8306#define DUK_JSON_DEC_REQSTACK 32
8307
11fdf7f2 8308/* How large a loop detection stack to use */
7c673cae 8309#define DUK_JSON_ENC_LOOPARRAY 64
7c673cae
FG
8310
8311/* Encoding state. Heap object references are all borrowed. */
8312typedef struct {
8313 duk_hthread *thr;
8314 duk_bufwriter_ctx bw; /* output bufwriter */
8315 duk_hobject *h_replacer; /* replacer function */
8316 duk_hstring *h_gap; /* gap (if empty string, NULL) */
7c673cae
FG
8317 duk_idx_t idx_proplist; /* explicit PropertyList */
8318 duk_idx_t idx_loop; /* valstack index of loop detection object */
8319 duk_small_uint_t flags;
8320 duk_small_uint_t flag_ascii_only;
8321 duk_small_uint_t flag_avoid_key_quotes;
8322#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
8323 duk_small_uint_t flag_ext_custom;
8324 duk_small_uint_t flag_ext_compatible;
11fdf7f2 8325 duk_small_uint_t flag_ext_custom_or_compatible;
7c673cae
FG
8326#endif
8327 duk_int_t recursion_depth;
8328 duk_int_t recursion_limit;
8329 duk_uint_t mask_for_undefined; /* type bit mask: types which certainly produce 'undefined' */
8330#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
8331 duk_small_uint_t stridx_custom_undefined;
8332 duk_small_uint_t stridx_custom_nan;
8333 duk_small_uint_t stridx_custom_neginf;
8334 duk_small_uint_t stridx_custom_posinf;
8335 duk_small_uint_t stridx_custom_function;
8336#endif
7c673cae 8337 duk_hobject *visiting[DUK_JSON_ENC_LOOPARRAY]; /* indexed by recursion_depth */
7c673cae
FG
8338} duk_json_enc_ctx;
8339
8340typedef struct {
8341 duk_hthread *thr;
8342 const duk_uint8_t *p;
8343 const duk_uint8_t *p_start;
8344 const duk_uint8_t *p_end;
8345 duk_idx_t idx_reviver;
8346 duk_small_uint_t flags;
8347#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
8348 duk_small_uint_t flag_ext_custom;
8349 duk_small_uint_t flag_ext_compatible;
11fdf7f2 8350 duk_small_uint_t flag_ext_custom_or_compatible;
7c673cae
FG
8351#endif
8352 duk_int_t recursion_depth;
8353 duk_int_t recursion_limit;
8354} duk_json_dec_ctx;
8355
8356#endif /* DUK_JSON_H_INCLUDED */
7c673cae
FG
8357/*
8358 * Ecmascript execution, support primitives.
8359 */
8360
8361#ifndef DUK_JS_H_INCLUDED
8362#define DUK_JS_H_INCLUDED
8363
8364/* Flags for call handling. */
11fdf7f2
TL
8365#define DUK_CALL_FLAG_IGNORE_RECLIMIT (1 << 0) /* duk_handle_call_xxx: call ignores C recursion limit (for errhandler calls) */
8366#define DUK_CALL_FLAG_CONSTRUCTOR_CALL (1 << 1) /* duk_handle_call_xxx: constructor call (i.e. called as 'new Foo()') */
8367#define DUK_CALL_FLAG_IS_RESUME (1 << 2) /* duk_handle_ecma_call_setup: setup for a resume() */
8368#define DUK_CALL_FLAG_IS_TAILCALL (1 << 3) /* duk_handle_ecma_call_setup: setup for a tail call */
8369#define DUK_CALL_FLAG_DIRECT_EVAL (1 << 4) /* call is a direct eval call */
7c673cae
FG
8370
8371/* Flags for duk_js_equals_helper(). */
8372#define DUK_EQUALS_FLAG_SAMEVALUE (1 << 0) /* use SameValue instead of non-strict equality */
8373#define DUK_EQUALS_FLAG_STRICT (1 << 1) /* use strict equality instead of non-strict equality */
8374
8375/* Flags for duk_js_compare_helper(). */
8376#define DUK_COMPARE_FLAG_EVAL_LEFT_FIRST (1 << 0) /* eval left argument first */
8377#define DUK_COMPARE_FLAG_NEGATE (1 << 1) /* negate result */
8378
8379/* conversions, coercions, comparison, etc */
8380DUK_INTERNAL_DECL duk_bool_t duk_js_toboolean(duk_tval *tv);
8381DUK_INTERNAL_DECL duk_double_t duk_js_tonumber(duk_hthread *thr, duk_tval *tv);
8382DUK_INTERNAL_DECL duk_double_t duk_js_tointeger_number(duk_double_t x);
8383DUK_INTERNAL_DECL duk_double_t duk_js_tointeger(duk_hthread *thr, duk_tval *tv);
8384DUK_INTERNAL_DECL duk_uint32_t duk_js_touint32(duk_hthread *thr, duk_tval *tv);
8385DUK_INTERNAL_DECL duk_int32_t duk_js_toint32(duk_hthread *thr, duk_tval *tv);
8386DUK_INTERNAL_DECL duk_uint16_t duk_js_touint16(duk_hthread *thr, duk_tval *tv);
8387DUK_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);
8388DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_string_helper(duk_hstring *h);
8389DUK_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);
8390DUK_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);
8391DUK_INTERNAL_DECL duk_small_int_t duk_js_string_compare(duk_hstring *h1, duk_hstring *h2);
8392#if 0 /* unused */
8393DUK_INTERNAL_DECL duk_small_int_t duk_js_buffer_compare(duk_heap *heap, duk_hbuffer *h1, duk_hbuffer *h2);
8394#endif
8395DUK_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);
8396DUK_INTERNAL_DECL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
8397DUK_INTERNAL_DECL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
8398DUK_INTERNAL_DECL duk_hstring *duk_js_typeof(duk_hthread *thr, duk_tval *tv_x);
8399
8400#define duk_js_equals(thr,tv_x,tv_y) \
8401 duk_js_equals_helper((thr), (tv_x), (tv_y), 0)
8402#define duk_js_strict_equals(tv_x,tv_y) \
8403 duk_js_equals_helper(NULL, (tv_x), (tv_y), DUK_EQUALS_FLAG_STRICT)
8404#define duk_js_samevalue(tv_x,tv_y) \
8405 duk_js_equals_helper(NULL, (tv_x), (tv_y), DUK_EQUALS_FLAG_SAMEVALUE)
8406
8407/* E5 Sections 11.8.1, 11.8.5; x < y */
8408#define duk_js_lessthan(thr,tv_x,tv_y) \
8409 duk_js_compare_helper((thr), (tv_x), (tv_Y), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST)
8410
8411/* E5 Sections 11.8.2, 11.8.5; x > y --> y < x */
8412#define duk_js_greaterthan(thr,tv_x,tv_y) \
8413 duk_js_compare_helper((thr), (tv_y), (tv_x), 0)
8414
8415/* E5 Sections 11.8.3, 11.8.5; x <= y --> not (x > y) --> not (y < x) */
8416#define duk_js_lessthanorequal(thr,tv_x,tv_y) \
8417 duk_js_compare_helper((thr), (tv_y), (tv_x), DUK_COMPARE_FLAG_NEGATE)
8418
8419/* E5 Sections 11.8.4, 11.8.5; x >= y --> not (x < y) */
8420#define duk_js_greaterthanorequal(thr,tv_x,tv_y) \
8421 duk_js_compare_helper((thr), (tv_x), (tv_y), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST | DUK_COMPARE_FLAG_NEGATE)
8422
8423/* identifiers and environment handling */
8424#if 0 /*unused*/
8425DUK_INTERNAL duk_bool_t duk_js_hasvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name);
8426#endif
8427DUK_INTERNAL_DECL duk_bool_t duk_js_getvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name, duk_bool_t throw_flag);
8428DUK_INTERNAL_DECL duk_bool_t duk_js_getvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_bool_t throw_flag);
8429DUK_INTERNAL_DECL void duk_js_putvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name, duk_tval *val, duk_bool_t strict);
8430DUK_INTERNAL_DECL void duk_js_putvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_bool_t strict);
8431#if 0 /*unused*/
8432DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name);
8433#endif
8434DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name);
8435DUK_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);
8436DUK_INTERNAL_DECL void duk_js_init_activation_environment_records_delayed(duk_hthread *thr, duk_activation *act);
8437DUK_INTERNAL_DECL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env, duk_hobject *func, duk_size_t regbase);
8438DUK_INTERNAL_DECL duk_hobject *duk_create_activation_environment_record(duk_hthread *thr, duk_hobject *func, duk_size_t idx_bottom);
8439DUK_INTERNAL_DECL
8440void duk_js_push_closure(duk_hthread *thr,
8441 duk_hcompiledfunction *fun_temp,
8442 duk_hobject *outer_var_env,
11fdf7f2
TL
8443 duk_hobject *outer_lex_env,
8444 duk_bool_t add_auto_proto);
7c673cae
FG
8445
8446/* call handling */
11fdf7f2
TL
8447DUK_INTERNAL_DECL duk_int_t duk_handle_call_protected(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags);
8448DUK_INTERNAL_DECL void duk_handle_call_unprotected(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags);
7c673cae
FG
8449DUK_INTERNAL_DECL duk_int_t duk_handle_safe_call(duk_hthread *thr, duk_safe_call_function func, duk_idx_t num_stack_args, duk_idx_t num_stack_res);
8450DUK_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);
8451
8452/* bytecode execution */
8453DUK_INTERNAL_DECL void duk_js_execute_bytecode(duk_hthread *exec_thr);
8454
8455#endif /* DUK_JS_H_INCLUDED */
7c673cae
FG
8456#ifndef DUK_NUMCONV_H_INCLUDED
8457#define DUK_NUMCONV_H_INCLUDED
8458
8459/*
8460 * Number-to-string conversion. The semantics of these is very tightly
8461 * bound with the Ecmascript semantics required for call sites.
8462 */
8463
8464/* Output a specified number of digits instead of using the shortest
8465 * form. Used for toPrecision() and toFixed().
8466 */
8467#define DUK_N2S_FLAG_FIXED_FORMAT (1 << 0)
8468
8469/* Force exponential format. Used for toExponential(). */
8470#define DUK_N2S_FLAG_FORCE_EXP (1 << 1)
8471
8472/* If number would need zero padding (for whole number part), use
8473 * exponential format instead. E.g. if input number is 12300, 3
8474 * digits are generated ("123"), output "1.23e+4" instead of "12300".
8475 * Used for toPrecision().
8476 */
8477#define DUK_N2S_FLAG_NO_ZERO_PAD (1 << 2)
8478
8479/* Digit count indicates number of fractions (i.e. an absolute
8480 * digit index instead of a relative one). Used together with
8481 * DUK_N2S_FLAG_FIXED_FORMAT for toFixed().
8482 */
8483#define DUK_N2S_FLAG_FRACTION_DIGITS (1 << 3)
8484
8485/*
8486 * String-to-number conversion
8487 */
8488
8489/* Maximum exponent value when parsing numbers. This is not strictly
8490 * compliant as there should be no upper limit, but as we parse the
8491 * exponent without a bigint, impose some limit.
8492 */
8493#define DUK_S2N_MAX_EXPONENT 1000000000
8494
8495/* Trim white space (= allow leading and trailing whitespace) */
8496#define DUK_S2N_FLAG_TRIM_WHITE (1 << 0)
8497
8498/* Allow exponent */
8499#define DUK_S2N_FLAG_ALLOW_EXP (1 << 1)
8500
8501/* Allow trailing garbage (e.g. treat "123foo" as "123) */
8502#define DUK_S2N_FLAG_ALLOW_GARBAGE (1 << 2)
8503
8504/* Allow leading plus sign */
8505#define DUK_S2N_FLAG_ALLOW_PLUS (1 << 3)
8506
8507/* Allow leading minus sign */
8508#define DUK_S2N_FLAG_ALLOW_MINUS (1 << 4)
8509
8510/* Allow 'Infinity' */
8511#define DUK_S2N_FLAG_ALLOW_INF (1 << 5)
8512
8513/* Allow fraction part */
8514#define DUK_S2N_FLAG_ALLOW_FRAC (1 << 6)
8515
8516/* Allow naked fraction (e.g. ".123") */
8517#define DUK_S2N_FLAG_ALLOW_NAKED_FRAC (1 << 7)
8518
8519/* Allow empty fraction (e.g. "123.") */
8520#define DUK_S2N_FLAG_ALLOW_EMPTY_FRAC (1 << 8)
8521
8522/* Allow empty string to be interpreted as 0 */
8523#define DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO (1 << 9)
8524
8525/* Allow leading zeroes (e.g. "0123" -> "123") */
8526#define DUK_S2N_FLAG_ALLOW_LEADING_ZERO (1 << 10)
8527
8528/* Allow automatic detection of hex base ("0x" or "0X" prefix),
8529 * overrides radix argument and forces integer mode.
8530 */
8531#define DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT (1 << 11)
8532
8533/* Allow automatic detection of octal base, overrides radix
8534 * argument and forces integer mode.
8535 */
8536#define DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT (1 << 12)
8537
8538/*
8539 * Prototypes
8540 */
8541
8542DUK_INTERNAL_DECL void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags);
8543DUK_INTERNAL_DECL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk_small_uint_t flags);
8544
8545#endif /* DUK_NUMCONV_H_INCLUDED */
7c673cae 8546/*
11fdf7f2
TL
8547 * Prototypes for built-in functions not automatically covered by the
8548 * header declarations emitted by genbuiltins.py.
7c673cae
FG
8549 */
8550
8551#ifndef DUK_BUILTIN_PROTOS_H_INCLUDED
8552#define DUK_BUILTIN_PROTOS_H_INCLUDED
8553
8554/* Buffer size needed for duk_bi_date_format_timeval().
8555 * Accurate value is 32 + 1 for NUL termination:
8556 * >>> len('+123456-01-23T12:34:56.123+12:34')
8557 * 32
8558 * Include additional space to be safe.
8559 */
8560#define DUK_BI_DATE_ISO8601_BUFSIZE 48
8561
8562/* Maximum length of CommonJS module identifier to resolve. Length includes
8563 * both current module ID, requested (possibly relative) module ID, and a
8564 * slash in between.
8565 */
8566#define DUK_BI_COMMONJS_MODULE_ID_LIMIT 256
8567
7c673cae
FG
8568/* Helpers exposed for internal use */
8569DUK_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);
8570DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_timeval_from_dparts(duk_double_t *dparts, duk_small_uint_t flags);
8571DUK_INTERNAL_DECL void duk_bi_date_format_timeval(duk_double_t timeval, duk_uint8_t *out_buf);
8572DUK_INTERNAL_DECL duk_bool_t duk_bi_date_is_leap_year(duk_int_t year);
8573DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_valid_range(duk_double_t x);
8574DUK_INTERNAL_DECL duk_bool_t duk_bi_date_year_in_valid_range(duk_double_t year);
8575DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_leeway_range(duk_double_t x);
11fdf7f2
TL
8576/* Built-in providers */
8577#if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY)
8578DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_gettimeofday(duk_context *ctx);
8579#endif
8580#if defined(DUK_USE_DATE_NOW_TIME)
8581DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_time(duk_context *ctx);
8582#endif
8583#if defined(DUK_USE_DATE_NOW_WINDOWS)
8584DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows(duk_context *ctx);
8585#endif
8586#if defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME)
8587DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d);
8588#endif
8589#if defined(DUK_USE_DATE_TZO_WINDOWS)
8590DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d);
8591#endif
8592#if defined(DUK_USE_DATE_PRS_STRPTIME)
8593DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_strptime(duk_context *ctx, const char *str);
8594#endif
8595#if defined(DUK_USE_DATE_PRS_GETDATE)
8596DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_getdate(duk_context *ctx, const char *str);
8597#endif
8598#if defined(DUK_USE_DATE_FMT_STRFTIME)
8599DUK_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);
8600#endif
7c673cae
FG
8601
8602DUK_INTERNAL_DECL
8603void duk_bi_json_parse_helper(duk_context *ctx,
8604 duk_idx_t idx_value,
8605 duk_idx_t idx_reviver,
8606 duk_small_uint_t flags);
8607DUK_INTERNAL_DECL
8608void duk_bi_json_stringify_helper(duk_context *ctx,
8609 duk_idx_t idx_value,
8610 duk_idx_t idx_replacer,
8611 duk_idx_t idx_space,
8612 duk_small_uint_t flags);
7c673cae 8613
11fdf7f2
TL
8614#endif /* DUK_BUILTIN_PROTOS_H_INCLUDED */
8615/*
8616 * Selftest code
8617 */
7c673cae 8618
11fdf7f2
TL
8619#ifndef DUK_SELFTEST_H_INCLUDED
8620#define DUK_SELFTEST_H_INCLUDED
7c673cae 8621
11fdf7f2
TL
8622#if defined(DUK_USE_SELF_TESTS)
8623DUK_INTERNAL_DECL void duk_selftest_run_tests(void);
8624#endif
7c673cae 8625
11fdf7f2 8626#endif /* DUK_SELFTEST_H_INCLUDED */
7c673cae 8627
11fdf7f2
TL
8628#endif /* DUK_INTERNAL_H_INCLUDED */
8629/*
8630 * Replacements for missing platform functions.
8631 *
8632 * Unlike the originals, fpclassify() and signbit() replacements don't
8633 * work on any floating point types, only doubles. The C typing here
8634 * mimics the standard prototypes.
7c673cae 8635 */
7c673cae 8636
11fdf7f2
TL
8637/* include removed: duk_internal.h */
8638
8639#if defined(DUK_USE_COMPUTED_NAN)
8640DUK_INTERNAL double duk_computed_nan;
7c673cae
FG
8641#endif
8642
11fdf7f2
TL
8643#if defined(DUK_USE_COMPUTED_INFINITY)
8644DUK_INTERNAL double duk_computed_infinity;
8645#endif
7c673cae 8646
11fdf7f2
TL
8647#if defined(DUK_USE_REPL_FPCLASSIFY)
8648DUK_INTERNAL int duk_repl_fpclassify(double x) {
8649 duk_double_union u;
8650 duk_uint_fast16_t expt;
8651 duk_small_int_t mzero;
7c673cae 8652
11fdf7f2
TL
8653 u.d = x;
8654 expt = (duk_uint_fast16_t) (u.us[DUK_DBL_IDX_US0] & 0x7ff0UL);
8655 if (expt > 0x0000UL && expt < 0x7ff0UL) {
8656 /* expt values [0x001,0x7fe] = normal */
8657 return DUK_FP_NORMAL;
8658 }
7c673cae 8659
11fdf7f2
TL
8660 mzero = (u.ui[DUK_DBL_IDX_UI1] == 0 && (u.ui[DUK_DBL_IDX_UI0] & 0x000fffffUL) == 0);
8661 if (expt == 0x0000UL) {
8662 /* expt 0x000 is zero/subnormal */
8663 if (mzero) {
8664 return DUK_FP_ZERO;
8665 } else {
8666 return DUK_FP_SUBNORMAL;
8667 }
8668 } else {
8669 /* expt 0xfff is infinite/nan */
8670 if (mzero) {
8671 return DUK_FP_INFINITE;
8672 } else {
8673 return DUK_FP_NAN;
8674 }
8675 }
8676}
8677#endif
7c673cae 8678
11fdf7f2
TL
8679#if defined(DUK_USE_REPL_SIGNBIT)
8680DUK_INTERNAL int duk_repl_signbit(double x) {
8681 duk_double_union u;
8682 u.d = x;
8683 return (int) (u.uc[DUK_DBL_IDX_UC0] & 0x80UL);
8684}
8685#endif
7c673cae 8686
11fdf7f2
TL
8687#if defined(DUK_USE_REPL_ISFINITE)
8688DUK_INTERNAL int duk_repl_isfinite(double x) {
8689 int c = DUK_FPCLASSIFY(x);
8690 if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
8691 return 0;
8692 } else {
8693 return 1;
8694 }
8695}
7c673cae
FG
8696#endif
8697
11fdf7f2
TL
8698#if defined(DUK_USE_REPL_ISNAN)
8699DUK_INTERNAL int duk_repl_isnan(double x) {
8700 int c = DUK_FPCLASSIFY(x);
8701 return (c == DUK_FP_NAN);
8702}
8703#endif
7c673cae 8704
11fdf7f2
TL
8705#if defined(DUK_USE_REPL_ISINF)
8706DUK_INTERNAL int duk_repl_isinf(double x) {
8707 int c = DUK_FPCLASSIFY(x);
8708 return (c == DUK_FP_INFINITE);
8709}
8710#endif
7c673cae
FG
8711/*
8712 * Shared error message strings
8713 *
8714 * To minimize code footprint, try to share error messages inside Duktape
8715 * code. Modern compilers will do this automatically anyway, this is mostly
8716 * for older compilers.
8717 */
8718
8719/* include removed: duk_internal.h */
8720
8721/* Mostly API and built-in method related */
8722DUK_INTERNAL const char *duk_str_internal_error = "internal error";
8723DUK_INTERNAL const char *duk_str_invalid_count = "invalid count";
8724DUK_INTERNAL const char *duk_str_invalid_call_args = "invalid call args";
8725DUK_INTERNAL const char *duk_str_not_constructable = "not constructable";
8726DUK_INTERNAL const char *duk_str_not_callable = "not callable";
8727DUK_INTERNAL const char *duk_str_not_extensible = "not extensible";
8728DUK_INTERNAL const char *duk_str_not_writable = "not writable";
8729DUK_INTERNAL const char *duk_str_not_configurable = "not configurable";
8730
8731DUK_INTERNAL const char *duk_str_invalid_context = "invalid context";
7c673cae 8732DUK_INTERNAL const char *duk_str_push_beyond_alloc_stack = "attempt to push beyond currently allocated stack";
11fdf7f2 8733DUK_INTERNAL const char *duk_str_not_buffer = "not buffer"; /* still in use with verbose messages */
7c673cae 8734DUK_INTERNAL const char *duk_str_unexpected_type = "unexpected type";
7c673cae
FG
8735DUK_INTERNAL const char *duk_str_defaultvalue_coerce_failed = "[[DefaultValue]] coerce failed";
8736DUK_INTERNAL const char *duk_str_number_outside_range = "number outside range";
8737DUK_INTERNAL const char *duk_str_not_object_coercible = "not object coercible";
8738DUK_INTERNAL const char *duk_str_string_too_long = "string too long";
8739DUK_INTERNAL const char *duk_str_buffer_too_long = "buffer too long";
8740DUK_INTERNAL const char *duk_str_sprintf_too_long = "sprintf message too long";
8741DUK_INTERNAL const char *duk_str_alloc_failed = "alloc failed";
8742DUK_INTERNAL const char *duk_str_pop_too_many = "attempt to pop too many entries";
8743DUK_INTERNAL const char *duk_str_wrong_buffer_type = "wrong buffer type";
7c673cae
FG
8744DUK_INTERNAL const char *duk_str_encode_failed = "encode failed";
8745DUK_INTERNAL const char *duk_str_decode_failed = "decode failed";
8746DUK_INTERNAL const char *duk_str_no_sourcecode = "no sourcecode";
8747DUK_INTERNAL const char *duk_str_concat_result_too_long = "concat result too long";
8748DUK_INTERNAL const char *duk_str_unimplemented = "unimplemented";
8749DUK_INTERNAL const char *duk_str_unsupported = "unsupported";
8750DUK_INTERNAL const char *duk_str_array_length_over_2g = "array length over 2G";
8751
8752/* JSON */
8753DUK_INTERNAL const char *duk_str_fmt_ptr = "%p";
8754DUK_INTERNAL const char *duk_str_fmt_invalid_json = "invalid json (at offset %ld)";
8755DUK_INTERNAL const char *duk_str_jsondec_reclimit = "json decode recursion limit";
8756DUK_INTERNAL const char *duk_str_jsonenc_reclimit = "json encode recursion limit";
8757DUK_INTERNAL const char *duk_str_cyclic_input = "cyclic input";
8758
8759/* Object property access */
8760DUK_INTERNAL const char *duk_str_proxy_revoked = "proxy revoked";
7c673cae
FG
8761DUK_INTERNAL const char *duk_str_invalid_base = "invalid base value";
8762DUK_INTERNAL const char *duk_str_strict_caller_read = "attempt to read strict 'caller'";
8763DUK_INTERNAL const char *duk_str_proxy_rejected = "proxy rejected";
8764DUK_INTERNAL const char *duk_str_invalid_array_length = "invalid array length";
8765DUK_INTERNAL const char *duk_str_array_length_write_failed = "array length write failed";
8766DUK_INTERNAL const char *duk_str_array_length_not_writable = "array length non-writable";
8767DUK_INTERNAL const char *duk_str_setter_undefined = "setter undefined";
8768DUK_INTERNAL const char *duk_str_redefine_virt_prop = "attempt to redefine virtual property";
8769DUK_INTERNAL const char *duk_str_invalid_descriptor = "invalid descriptor";
8770DUK_INTERNAL const char *duk_str_property_is_virtual = "property is virtual";
8771
8772/* Compiler */
8773DUK_INTERNAL const char *duk_str_parse_error = "parse error";
8774DUK_INTERNAL const char *duk_str_duplicate_label = "duplicate label";
8775DUK_INTERNAL const char *duk_str_invalid_label = "invalid label";
8776DUK_INTERNAL const char *duk_str_invalid_array_literal = "invalid array literal";
8777DUK_INTERNAL const char *duk_str_invalid_object_literal = "invalid object literal";
8778DUK_INTERNAL const char *duk_str_invalid_var_declaration = "invalid variable declaration";
8779DUK_INTERNAL const char *duk_str_cannot_delete_identifier = "cannot delete identifier";
8780DUK_INTERNAL const char *duk_str_invalid_expression = "invalid expression";
8781DUK_INTERNAL const char *duk_str_invalid_lvalue = "invalid lvalue";
8782DUK_INTERNAL const char *duk_str_expected_identifier = "expected identifier";
8783DUK_INTERNAL const char *duk_str_empty_expr_not_allowed = "empty expression not allowed";
8784DUK_INTERNAL const char *duk_str_invalid_for = "invalid for statement";
8785DUK_INTERNAL const char *duk_str_invalid_switch = "invalid switch statement";
8786DUK_INTERNAL const char *duk_str_invalid_break_cont_label = "invalid break/continue label";
8787DUK_INTERNAL const char *duk_str_invalid_return = "invalid return";
8788DUK_INTERNAL const char *duk_str_invalid_try = "invalid try";
8789DUK_INTERNAL const char *duk_str_invalid_throw = "invalid throw";
8790DUK_INTERNAL const char *duk_str_with_in_strict_mode = "with in strict mode";
8791DUK_INTERNAL const char *duk_str_func_stmt_not_allowed = "function statement not allowed";
8792DUK_INTERNAL const char *duk_str_unterminated_stmt = "unterminated statement";
8793DUK_INTERNAL const char *duk_str_invalid_arg_name = "invalid argument name";
8794DUK_INTERNAL const char *duk_str_invalid_func_name = "invalid function name";
8795DUK_INTERNAL const char *duk_str_invalid_getset_name = "invalid getter/setter name";
8796DUK_INTERNAL const char *duk_str_func_name_required = "function name required";
8797
7c673cae
FG
8798/* Regexp */
8799DUK_INTERNAL const char *duk_str_invalid_quantifier_no_atom = "quantifier without preceding atom";
8800DUK_INTERNAL const char *duk_str_invalid_quantifier_values = "quantifier values invalid (qmin > qmax)";
8801DUK_INTERNAL const char *duk_str_quantifier_too_many_copies = "quantifier expansion requires too many atom copies";
8802DUK_INTERNAL const char *duk_str_unexpected_closing_paren = "unexpected closing parenthesis";
8803DUK_INTERNAL const char *duk_str_unexpected_end_of_pattern = "unexpected end of pattern";
8804DUK_INTERNAL const char *duk_str_unexpected_regexp_token = "unexpected token in regexp";
8805DUK_INTERNAL const char *duk_str_invalid_regexp_flags = "invalid regexp flags";
8806DUK_INTERNAL const char *duk_str_invalid_backrefs = "invalid backreference(s)";
7c673cae
FG
8807
8808/* Limits */
8809DUK_INTERNAL const char *duk_str_valstack_limit = "valstack limit";
8810DUK_INTERNAL const char *duk_str_callstack_limit = "callstack limit";
8811DUK_INTERNAL const char *duk_str_catchstack_limit = "catchstack limit";
7c673cae
FG
8812DUK_INTERNAL const char *duk_str_prototype_chain_limit = "prototype chain limit";
8813DUK_INTERNAL const char *duk_str_bound_chain_limit = "function call bound chain limit";
8814DUK_INTERNAL const char *duk_str_c_callstack_limit = "C call stack depth limit";
8815DUK_INTERNAL const char *duk_str_compiler_recursion_limit = "compiler recursion limit";
8816DUK_INTERNAL const char *duk_str_bytecode_limit = "bytecode limit";
8817DUK_INTERNAL const char *duk_str_reg_limit = "register limit";
8818DUK_INTERNAL const char *duk_str_temp_limit = "temp limit";
8819DUK_INTERNAL const char *duk_str_const_limit = "const limit";
8820DUK_INTERNAL const char *duk_str_func_limit = "function limit";
8821DUK_INTERNAL const char *duk_str_regexp_compiler_recursion_limit = "regexp compiler recursion limit";
8822DUK_INTERNAL const char *duk_str_regexp_executor_recursion_limit = "regexp executor recursion limit";
8823DUK_INTERNAL const char *duk_str_regexp_executor_step_limit = "regexp step limit";
8824
8825/* Misc */
7c673cae
FG
8826/*
8827 * Debugging macro calls.
8828 */
8829
8830/* include removed: duk_internal.h */
8831
8832#ifdef DUK_USE_DEBUG
8833
8834/*
8835 * Debugging enabled
8836 */
8837
8838#include <stdio.h>
8839#include <stdlib.h>
8840#include <stdarg.h>
8841
8842#define DUK__DEBUG_BUFSIZE DUK_USE_DEBUG_BUFSIZE
8843DUK_LOCAL char duk__debug_buf[DUK__DEBUG_BUFSIZE];
8844
8845DUK_LOCAL const char *duk__get_level_string(duk_small_int_t level) {
8846 switch ((int) level) {
8847 case DUK_LEVEL_DEBUG:
8848 return "D";
8849 case DUK_LEVEL_DDEBUG:
8850 return "DD";
8851 case DUK_LEVEL_DDDEBUG:
8852 return "DDD";
8853 }
8854 return "???";
8855}
8856
8857#ifdef DUK_USE_DPRINT_COLORS
8858
8859/* http://en.wikipedia.org/wiki/ANSI_escape_code */
8860#define DUK__TERM_REVERSE "\x1b[7m"
8861#define DUK__TERM_BRIGHT "\x1b[1m"
8862#define DUK__TERM_RESET "\x1b[0m"
8863#define DUK__TERM_BLUE "\x1b[34m"
8864#define DUK__TERM_RED "\x1b[31m"
8865
8866DUK_LOCAL const char *duk__get_term_1(duk_small_int_t level) {
8867 DUK_UNREF(level);
8868 return (const char *) DUK__TERM_RED;
8869}
8870
8871DUK_LOCAL const char *duk__get_term_2(duk_small_int_t level) {
8872 switch ((int) level) {
8873 case DUK_LEVEL_DEBUG:
8874 return (const char *) (DUK__TERM_RESET DUK__TERM_BRIGHT);
8875 case DUK_LEVEL_DDEBUG:
8876 return (const char *) (DUK__TERM_RESET);
8877 case DUK_LEVEL_DDDEBUG:
8878 return (const char *) (DUK__TERM_RESET DUK__TERM_BLUE);
8879 }
8880 return (const char *) DUK__TERM_RESET;
8881}
8882
8883DUK_LOCAL const char *duk__get_term_3(duk_small_int_t level) {
8884 DUK_UNREF(level);
8885 return (const char *) DUK__TERM_RESET;
8886}
8887
8888#else
8889
8890DUK_LOCAL const char *duk__get_term_1(duk_small_int_t level) {
8891 DUK_UNREF(level);
8892 return (const char *) "";
8893}
8894
8895DUK_LOCAL const char *duk__get_term_2(duk_small_int_t level) {
8896 DUK_UNREF(level);
8897 return (const char *) "";
8898}
8899
8900DUK_LOCAL const char *duk__get_term_3(duk_small_int_t level) {
8901 DUK_UNREF(level);
8902 return (const char *) "";
8903}
8904
8905#endif /* DUK_USE_DPRINT_COLORS */
8906
8907#ifdef DUK_USE_VARIADIC_MACROS
8908
8909DUK_INTERNAL void duk_debug_log(duk_small_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...) {
8910 va_list ap;
8911
8912 va_start(ap, fmt);
8913
8914 DUK_MEMZERO((void *) duk__debug_buf, (size_t) DUK__DEBUG_BUFSIZE);
8915 duk_debug_vsnprintf(duk__debug_buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap);
8916
7c673cae
FG
8917 DUK_FPRINTF(DUK_STDERR, "%s[%s] %s:%ld (%s):%s %s%s\n",
8918 (const char *) duk__get_term_1(level),
8919 (const char *) duk__get_level_string(level),
8920 (const char *) file,
8921 (long) line,
8922 (const char *) func,
8923 (const char *) duk__get_term_2(level),
8924 (const char *) duk__debug_buf,
8925 (const char *) duk__get_term_3(level));
7c673cae
FG
8926 DUK_FFLUSH(DUK_STDERR);
8927
8928 va_end(ap);
8929}
8930
8931#else /* DUK_USE_VARIADIC_MACROS */
8932
8933DUK_INTERNAL char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE];
8934DUK_INTERNAL char duk_debug_line_stash[DUK_DEBUG_STASH_SIZE];
8935DUK_INTERNAL char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE];
8936DUK_INTERNAL duk_small_int_t duk_debug_level_stash;
8937
8938DUK_INTERNAL void duk_debug_log(const char *fmt, ...) {
8939 va_list ap;
8940 duk_small_int_t level = duk_debug_level_stash;
8941
8942 va_start(ap, fmt);
8943
8944 DUK_MEMZERO((void *) duk__debug_buf, (size_t) DUK__DEBUG_BUFSIZE);
8945 duk_debug_vsnprintf(duk__debug_buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap);
8946
7c673cae
FG
8947 DUK_FPRINTF(DUK_STDERR, "%s[%s] %s:%s (%s):%s %s%s\n",
8948 (const char *) duk__get_term_1(level),
8949 (const char *) duk__get_level_string(duk_debug_level_stash),
8950 (const char *) duk_debug_file_stash,
8951 (const char *) duk_debug_line_stash,
8952 (const char *) duk_debug_func_stash,
8953 (const char *) duk__get_term_2(level),
8954 (const char *) duk__debug_buf,
8955 (const char *) duk__get_term_3(level));
7c673cae
FG
8956 DUK_FFLUSH(DUK_STDERR);
8957
8958 va_end(ap);
8959}
8960
8961#endif /* DUK_USE_VARIADIC_MACROS */
8962
8963#else /* DUK_USE_DEBUG */
8964
8965/*
8966 * Debugging disabled
8967 */
8968
8969#endif /* DUK_USE_DEBUG */
7c673cae
FG
8970/*
8971 * Automatically generated by genbuiltins.py, do not edit!
8972 */
8973
8974/* include removed: duk_internal.h */
8975
11fdf7f2
TL
8976#if defined(DUK_USE_ROM_STRINGS)
8977#error ROM support not enabled, rerun make_dist.py with --rom-support
8978#else /* DUK_USE_ROM_STRINGS */
8979DUK_INTERNAL const duk_uint8_t duk_strings_data[1049] = {
898079,104,209,144,168,105,6,78,182,139,90,122,8,154,140,35,103,35,117,193,73,
89815,52,116,180,104,166,135,52,189,4,98,12,27,178,156,80,211,31,161,115,150,
898264,52,221,109,24,18,68,157,24,38,67,118,36,55,73,119,151,164,140,93,18,117,
8983128,153,201,228,201,205,2,250,8,196,24,232,104,82,146,40,232,193,48,118,
8984168,37,147,212,54,127,113,208,70,32,194,187,68,54,127,113,208,70,32,196,
8985123,68,54,127,113,209,44,12,121,7,208,70,32,194,186,134,207,236,126,219,
8986160,140,65,133,246,136,108,254,199,237,186,8,196,24,87,80,217,253,159,217,
8987116,17,136,48,190,209,13,159,217,253,151,65,24,131,12,233,86,224,79,236,
8988254,203,160,140,65,134,116,171,112,39,246,223,105,208,70,32,193,140,183,4,
898911,55,92,20,244,141,169,186,50,11,164,109,77,208,208,165,36,79,215,185,13,
8990153,34,110,204,241,32,6,66,84,11,112,200,84,52,157,124,92,242,70,120,45,64,
8991186,17,22,138,38,0,172,140,19,154,84,26,145,0,86,69,17,180,97,34,0,172,132,
899275,144,215,77,221,91,132,5,147,178,156,80,211,30,160,93,9,215,21,115,119,
8993169,49,75,211,138,26,101,205,222,68,157,47,78,40,105,151,55,120,204,156,
8994189,56,161,166,52,157,72,136,138,65,154,232,147,162,4,136,150,81,115,66,
8995208,210,37,96,148,250,134,140,151,39,212,125,255,221,125,73,80,209,146,233,
8996124,93,55,79,15,34,196,230,202,113,160,166,232,157,132,148,128,98,28,46,
8997114,200,6,153,180,96,73,19,74,113,67,76,103,5,36,20,211,70,140,133,67,72,
899849,245,160,235,81,212,52,168,106,39,132,253,111,80,210,161,168,158,5,245,
8999191,96,31,172,15,208,23,226,190,131,232,62,131,232,11,251,127,93,245,223,
900093,251,172,234,27,80,45,3,250,14,140,19,34,65,19,81,132,108,228,97,1,107,
900133,12,32,45,100,136,206,9,12,196,155,134,69,146,100,235,226,231,146,51,194,
900272,218,48,145,4,200,119,89,189,81,49,39,72,147,235,226,233,186,120,121,58,
9003226,167,90,124,93,55,107,71,137,33,68,68,130,64,206,75,189,209,156,144,84,
900444,141,3,8,137,187,178,156,80,211,26,110,242,100,230,146,120,121,8,48,76,6,
900589,26,105,157,65,196,201,213,145,166,153,212,28,76,157,113,75,34,78,62,14,
900638,73,105,228,142,136,178,48,141,152,228,73,150,83,0,148,39,137,75,67,73,
9007214,209,129,36,85,190,206,32,17,6,9,128,141,3,8,130,161,100,235,64,194,24,
900852,41,73,19,189,200,108,201,19,111,181,2,232,66,239,173,37,230,157,244,56,
9009153,4,225,145,27,233,93,22,1,114,62,251,80,69,128,121,247,213,146,228,109,
901079,190,212,17,35,106,125,246,78,164,68,68,111,175,23,217,45,13,33,119,208,
901168,210,38,250,192,61,91,233,80,208,45,25,36,81,190,156,13,26,201,19,239,
9012162,2,214,66,31,125,153,226,64,13,27,236,72,96,130,68,62,251,48,68,196,153,
9013119,217,157,18,56,156,199,161,100,42,26,250,77,36,140,122,40,144,19,34,9,
901424,246,103,139,172,150,56,125,145,1,17,29,44,112,250,183,0,100,24,200,218,
9015140,228,185,130,9,19,237,190,208,73,184,146,35,68,146,163,8,50,178,99,136,
901644,89,196,2,33,70,64,208,196,67,74,226,88,17,105,73,24,186,37,40,38,5,133,
9017161,89,4,183,25,115,119,86,227,118,83,138,26,103,255,223,209,106,141,25,11,
9018244,95,117,56,208,159,250,223,251,250,45,52,13,250,47,186,156,104,79,253,
9019111,253,253,22,144,210,253,23,221,78,52,39,254,187,254,254,139,77,67,75,
9020244,95,117,56,208,159,250,239,251,250,45,22,141,23,209,125,212,227,66,127,
9021235,63,239,69,163,69,247,83,141,9,255,165,12,72,5,16,64,145,10,32,76,71,64,
9022156,217,161,180,34,6,64,208,198,36,78,50,20,20,92,204,50,44,147,32,134,226,
902317,114,33,202,134,129,107,192,202,232,160,180,104,166,135,52,72,40,144,213,
902433,178,152,26,34,56,163,105,44,104,146,116,139,77,43,34,98,57,38,116,72,
9025179,60,93,97,206,56,52,240,242,56,163,168,34,81,57,178,153,42,228,12,182,
902658,22,66,89,19,57,68,176,74,68,35,104,195,18,239,116,102,114,94,100,104,
9027228,100,49,238,140,203,42,60,145,35,104,181,146,113,161,10,80,46,68,82,24,
9028245,145,132,108,228,148,54,100,137,64,34,13,100,153,222,1,40,6,33,223,20,
902984,19,34,95,23,76,130,153,6,103,208,43,64,141,41,130,104,17,112,130,44,96,
7c673cae 9030};
11fdf7f2 9031#endif /* DUK_USE_ROM_STRINGS */
7c673cae 9032
11fdf7f2
TL
9033#if defined(DUK_USE_ROM_OBJECTS)
9034#error ROM support not enabled, rerun make_dist.py with --rom-support
9035#else /* DUK_USE_ROM_OBJECTS */
9036/* native functions: 149 */
9037DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = {
7c673cae
FG
9038 duk_bi_array_constructor,
9039 duk_bi_array_constructor_is_array,
9040 duk_bi_array_prototype_concat,
9041 duk_bi_array_prototype_indexof_shared,
9042 duk_bi_array_prototype_iter_shared,
9043 duk_bi_array_prototype_join_shared,
9044 duk_bi_array_prototype_pop,
9045 duk_bi_array_prototype_push,
9046 duk_bi_array_prototype_reduce_shared,
9047 duk_bi_array_prototype_reverse,
9048 duk_bi_array_prototype_shift,
9049 duk_bi_array_prototype_slice,
9050 duk_bi_array_prototype_sort,
9051 duk_bi_array_prototype_splice,
9052 duk_bi_array_prototype_to_string,
9053 duk_bi_array_prototype_unshift,
9054 duk_bi_arraybuffer_constructor,
9055 duk_bi_arraybuffer_isview,
9056 duk_bi_boolean_constructor,
9057 duk_bi_boolean_prototype_tostring_shared,
9058 duk_bi_buffer_compare_shared,
9059 duk_bi_buffer_constructor,
9060 duk_bi_buffer_prototype_tostring_shared,
9061 duk_bi_buffer_readfield,
9062 duk_bi_buffer_slice_shared,
9063 duk_bi_buffer_writefield,
9064 duk_bi_dataview_constructor,
9065 duk_bi_date_constructor,
9066 duk_bi_date_constructor_now,
9067 duk_bi_date_constructor_parse,
9068 duk_bi_date_constructor_utc,
9069 duk_bi_date_prototype_get_shared,
9070 duk_bi_date_prototype_get_timezone_offset,
9071 duk_bi_date_prototype_set_shared,
9072 duk_bi_date_prototype_set_time,
9073 duk_bi_date_prototype_to_json,
9074 duk_bi_date_prototype_tostring_shared,
9075 duk_bi_date_prototype_value_of,
9076 duk_bi_duktape_object_act,
9077 duk_bi_duktape_object_compact,
9078 duk_bi_duktape_object_dec,
9079 duk_bi_duktape_object_enc,
9080 duk_bi_duktape_object_fin,
9081 duk_bi_duktape_object_gc,
9082 duk_bi_duktape_object_info,
9083 duk_bi_error_constructor_shared,
9084 duk_bi_error_prototype_filename_getter,
11fdf7f2 9085 duk_bi_error_prototype_filename_setter,
7c673cae 9086 duk_bi_error_prototype_linenumber_getter,
11fdf7f2 9087 duk_bi_error_prototype_linenumber_setter,
7c673cae 9088 duk_bi_error_prototype_stack_getter,
11fdf7f2 9089 duk_bi_error_prototype_stack_setter,
7c673cae
FG
9090 duk_bi_error_prototype_to_string,
9091 duk_bi_function_constructor,
9092 duk_bi_function_prototype,
9093 duk_bi_function_prototype_apply,
9094 duk_bi_function_prototype_bind,
9095 duk_bi_function_prototype_call,
9096 duk_bi_function_prototype_to_string,
9097 duk_bi_global_object_decode_uri,
9098 duk_bi_global_object_decode_uri_component,
9099 duk_bi_global_object_encode_uri,
9100 duk_bi_global_object_encode_uri_component,
9101 duk_bi_global_object_escape,
9102 duk_bi_global_object_eval,
9103 duk_bi_global_object_is_finite,
9104 duk_bi_global_object_is_nan,
9105 duk_bi_global_object_parse_float,
9106 duk_bi_global_object_parse_int,
9107 duk_bi_global_object_print_helper,
9108 duk_bi_global_object_require,
9109 duk_bi_global_object_unescape,
9110 duk_bi_json_object_parse,
9111 duk_bi_json_object_stringify,
9112 duk_bi_logger_constructor,
9113 duk_bi_logger_prototype_fmt,
9114 duk_bi_logger_prototype_log_shared,
9115 duk_bi_logger_prototype_raw,
9116 duk_bi_math_object_max,
9117 duk_bi_math_object_min,
9118 duk_bi_math_object_onearg_shared,
9119 duk_bi_math_object_random,
9120 duk_bi_math_object_twoarg_shared,
9121 duk_bi_nodejs_buffer_byte_length,
9122 duk_bi_nodejs_buffer_concat,
9123 duk_bi_nodejs_buffer_constructor,
9124 duk_bi_nodejs_buffer_copy,
9125 duk_bi_nodejs_buffer_fill,
9126 duk_bi_nodejs_buffer_is_buffer,
9127 duk_bi_nodejs_buffer_is_encoding,
9128 duk_bi_nodejs_buffer_tojson,
9129 duk_bi_nodejs_buffer_tostring,
9130 duk_bi_nodejs_buffer_write,
9131 duk_bi_number_constructor,
9132 duk_bi_number_prototype_to_exponential,
9133 duk_bi_number_prototype_to_fixed,
9134 duk_bi_number_prototype_to_locale_string,
9135 duk_bi_number_prototype_to_precision,
9136 duk_bi_number_prototype_to_string,
9137 duk_bi_number_prototype_value_of,
9138 duk_bi_object_constructor,
9139 duk_bi_object_constructor_create,
9140 duk_bi_object_constructor_define_properties,
9141 duk_bi_object_constructor_define_property,
9142 duk_bi_object_constructor_get_own_property_descriptor,
9143 duk_bi_object_constructor_is_extensible,
9144 duk_bi_object_constructor_is_sealed_frozen_shared,
9145 duk_bi_object_constructor_keys_shared,
9146 duk_bi_object_constructor_prevent_extensions,
9147 duk_bi_object_constructor_seal_freeze_shared,
9148 duk_bi_object_getprototype_shared,
9149 duk_bi_object_prototype_has_own_property,
9150 duk_bi_object_prototype_is_prototype_of,
9151 duk_bi_object_prototype_property_is_enumerable,
9152 duk_bi_object_prototype_to_locale_string,
9153 duk_bi_object_prototype_to_string,
9154 duk_bi_object_prototype_value_of,
9155 duk_bi_object_setprototype_shared,
9156 duk_bi_pointer_constructor,
9157 duk_bi_pointer_prototype_tostring_shared,
9158 duk_bi_proxy_constructor,
9159 duk_bi_regexp_constructor,
9160 duk_bi_regexp_prototype_exec,
9161 duk_bi_regexp_prototype_test,
9162 duk_bi_regexp_prototype_to_string,
9163 duk_bi_string_constructor,
9164 duk_bi_string_constructor_from_char_code,
9165 duk_bi_string_prototype_caseconv_shared,
9166 duk_bi_string_prototype_char_at,
9167 duk_bi_string_prototype_char_code_at,
9168 duk_bi_string_prototype_concat,
9169 duk_bi_string_prototype_indexof_shared,
9170 duk_bi_string_prototype_locale_compare,
9171 duk_bi_string_prototype_match,
9172 duk_bi_string_prototype_replace,
9173 duk_bi_string_prototype_search,
9174 duk_bi_string_prototype_slice,
9175 duk_bi_string_prototype_split,
9176 duk_bi_string_prototype_substr,
9177 duk_bi_string_prototype_substring,
9178 duk_bi_string_prototype_to_string,
9179 duk_bi_string_prototype_trim,
9180 duk_bi_thread_constructor,
9181 duk_bi_thread_current,
9182 duk_bi_thread_resume,
9183 duk_bi_thread_yield,
9184 duk_bi_type_error_thrower,
9185 duk_bi_typedarray_constructor,
9186 duk_bi_typedarray_set,
9187};
11fdf7f2
TL
9188#if defined(DUK_USE_BUILTIN_INITJS)
9189DUK_INTERNAL const duk_uint8_t duk_initjs_data[204] = {
7c673cae
FG
919040,102,117,110,99,116,105,111,110,40,100,44,97,41,123,102,117,110,99,116,
9191105,111,110,32,98,40,97,44,98,44,99,41,123,79,98,106,101,99,116,46,100,101,
9192102,105,110,101,80,114,111,112,101,114,116,121,40,97,44,98,44,123,118,97,
9193108,117,101,58,99,44,119,114,105,116,97,98,108,101,58,33,48,44,101,110,117,
9194109,101,114,97,98,108,101,58,33,49,44,99,111,110,102,105,103,117,114,97,98,
9195108,101,58,33,48,125,41,125,98,40,97,46,76,111,103,103,101,114,44,34,99,
9196108,111,103,34,44,110,101,119,32,97,46,76,111,103,103,101,114,40,34,67,34,
11fdf7f2
TL
919741,41,59,98,40,97,44,34,109,111,100,76,111,97,100,101,100,34,44,79,98,106,
9198101,99,116,46,99,114,101,97,116,101,40,110,117,108,108,41,41,125,41,40,116,
9199104,105,115,44,68,117,107,116,97,112,101,41,59,10,0,
7c673cae
FG
9200};
9201#endif /* DUK_USE_BUILTIN_INITJS */
11fdf7f2
TL
9202#if defined(DUK_USE_DOUBLE_LE)
9203DUK_INTERNAL const duk_uint8_t duk_builtins_data[3833] = {
9204105,195,75,32,3,148,52,154,248,9,26,13,128,112,105,0,240,22,20,26,95,124,6,
9205152,52,137,0,120,99,74,239,129,18,70,241,191,2,98,13,79,32,42,88,210,90,2,
9206240,1,50,141,37,168,76,94,216,118,69,229,203,127,44,0,84,163,73,106,21,75,
920714,236,249,98,242,229,191,150,0,46,81,164,181,14,165,151,54,94,89,119,99,
9208203,23,151,45,252,176,1,146,141,37,168,93,63,59,186,97,241,23,151,45,252,
9209176,1,178,141,37,168,77,79,60,50,197,229,203,127,44,0,116,163,73,106,17,86,
9210148,152,188,185,111,229,128,15,148,129,198,137,36,58,166,142,91,251,212,
9211243,195,44,94,92,183,242,13,79,8,45,14,91,252,121,148,52,199,120,63,72,105,
921221,240,118,128,210,237,224,245,17,165,43,224,211,55,231,207,151,148,161,70,
9213145,0,31,40,107,26,2,18,138,26,228,192,142,0,16,161,174,76,9,74,26,228,192,
9214158,0,8,161,174,76,10,96,2,42,26,228,192,174,0,26,161,174,76,11,96,3,74,26,
9215228,192,190,0,44,161,174,76,12,96,3,202,26,228,192,206,0,70,161,169,84,14,
9216202,3,255,254,32,234,0,0,0,0,0,0,7,195,248,119,0,0,0,0,0,0,3,193,252,57,
9217136,1,152,32,16,194,0,166,24,6,49,0,57,138,2,12,96,18,99,128,163,32,5,153,
921840,76,94,216,118,69,229,203,127,35,41,10,165,135,118,124,177,121,114,223,
9219200,203,67,169,101,205,151,150,93,216,242,197,229,203,127,35,49,11,167,231,
9220119,76,62,34,242,229,191,145,154,132,212,243,195,44,94,92,183,242,51,144,
9221138,180,164,197,229,203,127,35,60,6,26,0,52,208,193,226,117,215,211,15,12,
9222166,146,11,67,150,255,30,77,24,58,113,64,243,92,8,27,0,68,217,130,70,212,
922319,54,224,161,185,5,77,216,44,111,65,115,126,12,28,16,100,225,156,16,32,18,
922417,195,15,46,121,100,238,232,136,136,87,12,60,185,229,141,179,126,30,136,
9225100,130,233,231,59,12,228,34,66,52,243,141,167,118,158,153,80,73,9,201,151,
922630,252,153,106,210,146,118,72,150,76,184,247,228,203,86,148,152,123,246,
9227240,223,187,46,238,135,132,132,229,221,143,126,76,181,105,73,61,36,75,46,
9228236,123,242,101,171,74,76,61,251,120,111,221,151,119,67,226,65,178,243,199,
9229135,134,83,242,66,58,238,203,207,30,30,25,81,201,5,225,203,78,238,136,163,
9230208,92,59,50,242,232,138,62,0,2,38,163,19,255,255,224,142,80,192,0,20,31,
9231240,14,135,103,203,210,135,45,253,55,244,243,195,44,252,205,197,0,1,18,221,
923282,0,3,24,207,151,164,254,251,168,114,223,195,47,46,158,98,101,231,143,150,
9233158,29,55,242,104,68,79,62,94,147,251,238,161,203,127,12,188,186,121,157,
9234135,110,94,109,100,131,99,229,151,15,76,172,168,8,89,217,16,201,151,54,157,
9235217,104,114,223,195,47,46,154,114,243,102,68,19,158,92,59,27,73,6,205,203,
923646,95,89,91,74,0,3,17,225,203,47,108,187,186,69,241,211,46,238,122,119,238,
9237230,216,72,70,158,116,242,225,217,151,35,81,33,26,121,198,229,191,214,93,
9238205,69,0,1,134,105,231,23,199,76,187,185,233,197,179,43,73,32,154,242,249,
9239230,214,80,0,31,255,193,2,38,103,110,117,24,81,115,0,78,228,0,161,208,16,
9240237,24,121,207,239,186,135,45,252,50,242,233,229,188,144,221,60,232,114,
9241223,211,127,79,60,50,207,204,224,72,167,14,91,248,101,229,211,204,158,113,
9242119,117,219,151,150,28,91,50,184,144,40,95,224,0,15,248,64,4,20,78,129,5,
9243195,195,134,207,38,232,130,99,195,179,97,201,244,19,22,157,217,14,15,130,
9244135,254,0,48,125,60,224,242,229,135,200,9,1,255,12,2,162,136,112,2,112,80,
9245128,0,193,177,239,221,143,15,64,35,224,152,20,144,62,27,248,3,2,9,195,175,
924661,0,231,208,126,89,123,101,229,207,40,72,32,188,244,105,205,208,40,16,94,
9247123,52,227,202,22,136,39,61,252,186,6,18,13,207,134,205,56,242,134,175,65,
9248250,238,231,163,78,110,129,231,208,125,59,178,101,241,63,48,25,248,0,12,47,
9249102,30,125,36,238,201,151,196,252,192,103,255,255,240,92,189,178,242,242,8,
9250105,4,231,191,110,80,67,80,0,24,62,109,252,162,225,199,160,16,212,0,10,7,
9251183,15,0,67,80,0,56,54,109,59,58,101,228,8,106,0,9,6,229,151,39,92,121,66,
925215,192,0,97,124,178,228,235,143,45,45,57,244,116,8,63,255,255,10,39,248,0,
9253195,51,114,223,182,30,140,60,161,239,201,149,248,248,31,241,0,140,80,129,
9254202,10,49,128,10,35,1,6,199,163,15,40,61,32,9,10,199,163,15,40,123,242,101,
9255131,210,4,144,108,123,247,99,195,210,8,250,15,167,118,76,190,39,230,131,52,
9256133,236,195,207,164,157,217,50,248,159,154,12,212,0,6,27,179,126,60,59,50,
9257195,223,183,134,30,89,97,9,5,219,135,166,61,16,164,131,242,203,195,102,28,
9258121,97,145,6,231,151,15,44,122,33,201,5,231,179,78,60,177,8,130,243,225,
9259179,79,72,148,66,121,245,197,207,167,45,59,179,197,162,23,211,124,205,253,
9260242,242,135,135,158,87,240,68,122,111,153,191,30,29,153,102,111,239,151,
9261148,60,60,242,191,130,23,211,125,94,28,50,242,135,135,158,87,240,128,0,196,
9262122,111,153,191,30,29,153,106,240,225,151,148,60,60,242,191,132,0,6,9,211,
9263150,157,177,160,131,115,235,139,159,78,81,72,10,47,248,0,3,254,40,17,138,
926448,66,136,152,64,0,66,129,48,5,27,252,88,76,216,54,47,214,131,50,172,88,31,
9265255,255,255,255,255,253,239,240,153,178,103,95,173,6,101,88,176,0,64,0,0,0,
92660,0,0,3,168,0,0,0,0,0,0,31,15,241,26,19,233,201,169,38,180,91,242,103,70,
9267147,58,77,75,48,0,0,0,0,0,0,60,31,226,51,162,199,131,82,77,104,183,228,206,
9268141,38,116,154,150,96,0,0,0,0,0,0,120,127,128,15,248,192,70,40,0,0,0,0,0,0,
92690,0,3,10,44,68,9,216,8,20,49,130,15,211,124,109,62,50,228,95,36,55,166,248,
9270190,56,111,221,151,119,77,56,118,47,18,23,211,125,14,89,113,233,231,167,
9271126,230,18,5,31,252,0,224,188,48,242,231,148,116,144,58,181,33,143,127,64,
9272247,111,238,56,0,127,199,2,49,72,0,0,0,0,0,0,248,127,180,81,36,4,51,166,
9273248,152,122,101,167,211,150,157,217,201,2,0,3,12,233,190,166,157,185,105,
9274244,229,167,118,114,64,128,1,4,228,129,0,3,137,116,223,51,126,60,59,50,196,
9275195,211,45,62,156,180,238,206,72,16,0,72,151,77,243,55,227,195,179,45,77,
927659,114,211,233,203,78,236,228,129,0,5,10,73,2,0,12,21,18,4,0,28,82,35,32,
927780,74,8,62,124,189,42,105,219,148,148,16,188,249,122,70,235,179,101,156,
9278184,121,15,132,0,34,29,159,47,74,181,33,198,235,179,101,156,184,121,15,132,
92790,38,17,159,47,73,187,247,116,208,62,16,0,168,94,124,189,42,212,135,55,126,
9280238,154,7,194,0,23,7,207,151,164,76,61,50,143,132,0,50,21,159,47,74,181,33,
9281196,195,211,40,248,64,3,96,217,242,244,137,135,200,248,64,3,161,57,242,244,
9282171,82,28,76,62,71,194,0,31,8,207,151,164,141,253,121,115,31,8,0,132,47,62,
928394,149,106,67,145,191,175,46,99,225,0,17,133,103,203,210,110,157,221,122,
9284101,230,62,16,1,40,110,124,189,42,212,135,55,78,238,189,50,243,31,8,0,156,
928543,62,94,148,242,227,223,187,39,49,240,128,10,67,115,229,233,86,164,58,121,
9286113,239,221,147,152,248,64,5,97,249,242,244,155,167,102,205,60,242,227,223,
9287187,39,49,240,128,11,68,179,229,233,86,164,57,186,118,108,211,207,46,61,
9288251,178,115,31,8,0,188,71,62,94,149,52,237,203,235,126,236,179,243,102,231,
9289151,161,0,32,252,242,244,169,167,110,82,34,67,249,229,233,55,78,205,154,
9290121,229,199,191,118,78,100,37,0,24,137,115,203,210,173,72,115,116,236,217,
9291167,158,92,123,247,100,230,66,80,1,152,87,60,189,41,229,199,191,118,78,100,
929243,224,3,80,222,121,122,85,169,14,158,92,123,247,100,230,66,190,0,55,10,
9293231,151,164,221,59,186,244,203,204,133,252,0,114,27,207,47,74,181,33,205,
9294211,187,175,76,188,200,95,192,7,97,28,242,244,145,191,175,46,100,51,224,3,
9295208,190,121,122,85,169,14,70,254,188,185,144,207,128,15,193,249,229,233,19,
929615,76,164,37,0,32,133,115,203,210,173,72,113,48,244,202,66,80,2,24,71,60,
9297189,38,239,221,211,65,10,248,1,20,47,158,94,149,106,67,155,191,119,77,4,43,
9298224,4,112,190,121,122,70,235,179,101,156,184,121,16,191,128,18,67,185,229,
9299233,86,164,56,221,118,108,179,151,15,34,23,240,2,88,62,124,189,44,229,195,
9300200,124,32,4,208,126,121,122,89,203,135,145,9,64,9,194,145,254,0,0,255,144,
930124,100,130,14,0,16,176,2,192,129,11,33,12,1,168,193,108,96,186,48,95,32,0,
93020,0,0,0,0,0,0,56,38,95,25,113,189,18,9,211,47,62,143,100,20,95,0,20,159,
9303240,0,7,252,144,162,241,2,195,66,7,11,89,204,140,197,252,229,197,226,230,
9304115,3,16,69,19,64,5,43,252,0,9,255,40,16,188,33,49,123,97,217,23,151,45,
9305252,131,66,7,0,20,191,240,0,39,252,176,66,240,133,82,195,187,62,88,188,185,
9306111,228,26,16,56,0,166,127,128,1,63,230,2,23,132,58,150,92,217,121,101,221,
9307143,44,94,92,183,242,13,8,28,0,83,127,192,0,159,243,65,11,194,23,79,206,
9308238,152,124,69,229,203,127,32,208,129,192,5,59,252,0,9,255,56,16,188,33,53,
930960,240,203,23,151,45,252,131,66,7,0,20,255,240,0,39,252,240,66,240,132,85,
9310165,38,47,46,91,249,6,132,14,0,31,255,228,64,98,192,105,87,20,139,10,191,5,
931164,130,76,156,197,132,1,101,91,91,187,22,176,36,8,28,201,204,160,119,156,
9312253,127,33,23,115,31,193,102,79,142,202,44,15,232,34,182,84,113,95,115,248,
931352,201,241,216,176,139,0,59,148,152,85,239,47,108,254,5,66,76,1,130,212,69,
931479,178,16,148,8,61,58,52,170,49,190,202,6,105,219,251,52,245,7,49,252,22,
9315157,26,85,25,64,205,59,127,102,158,160,246,63,74,7,135,23,53,2,65,48,227,
9316223,205,64,160,0,48,76,60,244,238,80,40,0,20,19,15,76,59,148,10,0,7,5,195,
9317211,14,230,74,72,130,99,203,167,98,129,64,1,32,120,247,243,80,40,0,44,15,
931847,142,10,5,0,6,130,230,217,191,127,37,2,128,3,192,246,111,206,160,80,0,
9319136,30,220,62,19,151,160,123,116,238,79,94,129,240,223,221,73,32,0,48,110,
932088,119,100,223,181,68,16,94,91,250,238,200,160,80,0,152,31,61,59,148,10,0,
932121,4,231,199,151,69,2,128,5,192,250,97,220,160,80,0,192,127,255,128,20,23,
9322134,30,92,242,164,34,19,207,167,45,59,179,233,205,229,37,129,127,255,0,0,
9323191,255,128,0,63,255,197,131,246,203,203,158,157,251,160,0,0,0,0,0,12,98,
9324160,3,166,156,30,53,32,249,165,131,76,223,159,62,94,70,172,114,16,176,144,
932560,56,250,19,18,5,159,25,89,32,121,180,238,42,30,129,229,221,140,164,122,7,
9326147,46,50,129,232,62,61,251,120,97,199,208,156,129,83,127,0,50,250,69,3,
9327252,131,32,248,250,242,229,151,119,72,240,3,254,148,0,2,168,254,0,0,255,
9328167,0,33,68,88,32,0,33,64,176,2,170,254,0,0,255,169,0,33,69,220,32,0,33,67,
9329184,2,172,254,0,0,255,171,8,137,144,0,0,0,0,0,0,0,128,68,73,4,195,187,126,
9330226,8,4,178,16,41,164,32,147,7,136,52,193,240,0,18,17,48,124,0,8,133,76,31,
93310,3,33,147,7,192,1,8,116,193,240,0,82,127,255,132,47,65,11,137,191,174,45,
9332153,98,242,229,191,144,105,4,95,47,46,91,249,32,211,185,6,94,92,183,242,65,
9333163,14,236,155,52,238,206,0,85,255,192,6,13,167,157,109,57,123,136,144,31,
9334245,192,3,5,231,179,78,60,163,9,0,2,10,199,248,0,3,254,192,4,32,249,242,
9335244,147,187,163,129,116,128,24,66,51,229,233,87,78,238,142,5,210,0,65,8,
9336207,151,164,157,221,24,182,23,72,1,140,39,62,94,149,116,238,232,197,176,
9337186,64,8,97,25,242,244,147,187,163,54,66,233,0,50,132,231,203,210,174,157,
9338221,25,178,23,72,1,20,43,62,94,145,182,111,195,209,155,33,116,128,17,194,
9339179,229,233,27,102,252,61,27,52,23,72,1,36,31,158,94,146,119,116,112,50,
9340208,3,8,71,60,189,42,233,221,209,192,203,64,8,33,28,242,244,147,187,163,22,
9341195,45,0,49,132,243,203,210,174,157,221,24,182,25,104,1,12,35,158,94,146,
9342119,116,102,200,101,160,6,80,158,121,122,85,211,187,163,54,67,45,0,34,133,
9343115,203,210,54,205,248,122,51,100,50,208,2,56,87,60,189,35,108,223,135,163,
9344102,131,45,0,36,7,255,248,1,11,50,136,132,115,235,139,15,46,88,124,140,36,
93450,4,43,79,224,139,16,0,0,0,0,0,0,60,15,192,101,253,152,0,5,109,252,17,98,0,
93460,0,0,0,0,7,129,248,12,191,181,0,0,174,63,130,44,64,0,0,0,0,0,0,240,63,1,
9347151,246,224,0,21,215,240,69,136,0,0,0,0,0,0,0,8,0,50,254,228,0,2,188,254,8,
9348177,0,0,0,0,0,0,0,1,0,6,95,221,128,0,87,223,193,22,32,0,0,0,0,0,0,8,32,0,
9349203,251,208,0,11,3,248,34,196,0,0,0,0,0,0,1,4,0,25,127,126,0,1,97,127,4,88,
9350128,0,0,0,0,0,0,32,128,3,47,240,64,0,44,79,224,139,16,0,0,0,0,0,0,8,16,0,
9351101,254,24,0,5,141,252,1,96,216,247,238,199,135,162,162,33,90,121,197,221,
9352143,126,77,59,179,172,146,17,167,156,46,185,179,101,228,176,65,89,77,16,
9353124,123,246,240,195,203,40,162,64,0,193,255,138,5,144,158,89,112,228,171,
935439,119,71,2,232,132,114,203,135,36,157,221,28,11,164,0,66,25,203,46,28,149,
9355100,238,232,197,180,200,162,233,0,1,134,114,203,135,37,89,59,186,49,109,10,
935640,186,64,2,97,124,178,225,201,39,119,70,45,166,69,23,72,0,140,47,150,92,
935757,36,238,232,197,180,40,162,233,0,25,134,114,203,135,37,89,59,186,51,101,
935850,40,186,64,0,161,156,178,225,201,86,78,238,140,217,66,138,46,144,0,168,
935995,44,184,114,73,221,209,155,41,145,69,210,0,37,11,229,151,14,73,59,186,51,
9360101,10,40,186,64,6,161,124,178,225,201,27,102,252,61,38,69,23,72,0,28,47,
9361150,92,57,35,108,223,135,164,40,162,233,0,11,134,114,203,135,36,77,253,113,
9362108,203,50,40,186,64,1,33,156,178,225,201,19,127,92,91,50,194,138,46,144,0,
9363200,87,44,184,114,85,147,187,164,200,162,237,0,5,133,114,203,135,37,89,59,
9364186,66,138,46,208,0,216,79,44,184,114,73,221,210,100,81,118,128,10,194,121,
9365101,195,146,78,238,144,162,139,180,0,118,21,223,150,158,153,106,201,221,
9366209,192,203,33,61,249,105,233,150,78,238,142,6,90,0,33,13,239,203,79,76,
9367181,100,238,232,197,180,200,163,45,0,1,134,247,229,167,166,90,178,119,116,
936898,218,20,81,150,128,4,195,59,242,211,211,44,157,221,24,182,153,20,101,160,
93692,48,206,252,180,244,203,39,119,70,45,161,69,25,104,0,204,55,191,45,61,50,
9370213,147,187,163,54,83,34,140,180,0,10,27,223,150,158,153,106,201,221,209,
9371155,40,81,70,90,0,21,12,239,203,79,76,178,119,116,102,202,100,81,150,128,9,
937267,59,242,211,211,44,157,221,25,178,133,20,101,160,3,80,206,252,180,244,
9373203,27,102,252,61,38,69,25,104,0,28,51,191,45,61,50,198,217,191,15,72,81,
937470,90,0,23,13,239,203,79,76,177,55,245,197,179,44,200,163,45,0,4,134,247,
9375229,167,166,88,155,250,226,217,150,20,81,150,128,6,66,251,242,211,211,45,
937689,59,186,76,138,51,16,0,88,95,126,90,122,101,171,39,119,72,81,70,98,0,27,
937710,239,203,79,76,178,119,116,153,20,102,32,2,176,174,252,180,244,203,39,
9378119,72,81,70,98,0,58,40,173,176,82,90,4,19,54,157,155,21,217,6,203,199,174,
937929,156,197,9,7,199,191,111,12,60,178,138,20,0,6,9,143,127,15,42,208,130,
9380243,217,167,30,81,132,65,123,242,211,211,42,228,0,
7c673cae 9381};
11fdf7f2
TL
9382#elif defined(DUK_USE_DOUBLE_BE)
9383DUK_INTERNAL const duk_uint8_t duk_builtins_data[3833] = {
9384105,195,75,32,3,148,52,154,248,9,26,13,128,112,105,0,240,22,20,26,95,124,6,
9385152,52,137,0,120,99,74,239,129,18,70,241,191,2,98,13,79,32,42,88,210,90,2,
9386240,1,50,141,37,168,76,94,216,118,69,229,203,127,44,0,84,163,73,106,21,75,
938714,236,249,98,242,229,191,150,0,46,81,164,181,14,165,151,54,94,89,119,99,
9388203,23,151,45,252,176,1,146,141,37,168,93,63,59,186,97,241,23,151,45,252,
9389176,1,178,141,37,168,77,79,60,50,197,229,203,127,44,0,116,163,73,106,17,86,
9390148,152,188,185,111,229,128,15,148,129,198,137,36,58,166,142,91,251,212,
9391243,195,44,94,92,183,242,13,79,8,45,14,91,252,121,148,52,199,120,63,72,105,
939221,240,118,128,210,237,224,245,17,165,43,224,211,55,231,207,151,148,161,70,
9393145,0,31,40,107,26,2,18,138,26,228,192,142,0,16,161,174,76,9,74,26,228,192,
9394158,0,8,161,174,76,10,96,2,42,26,228,192,174,0,26,161,174,76,11,96,3,74,26,
9395228,192,190,0,44,161,174,76,12,96,3,202,26,228,192,206,0,70,161,169,84,14,
9396202,3,255,254,32,234,3,255,192,0,0,0,0,0,0,119,1,255,192,0,0,0,0,0,0,57,
9397136,1,152,32,16,194,0,166,24,6,49,0,57,138,2,12,96,18,99,128,163,32,5,153,
939840,76,94,216,118,69,229,203,127,35,41,10,165,135,118,124,177,121,114,223,
9399200,203,67,169,101,205,151,150,93,216,242,197,229,203,127,35,49,11,167,231,
9400119,76,62,34,242,229,191,145,154,132,212,243,195,44,94,92,183,242,51,144,
9401138,180,164,197,229,203,127,35,60,6,26,0,52,208,193,226,117,215,211,15,12,
9402166,146,11,67,150,255,30,77,24,58,113,64,243,92,8,27,0,68,217,130,70,212,
940319,54,224,161,185,5,77,216,44,111,65,115,126,12,28,16,100,225,156,16,32,18,
940417,195,15,46,121,100,238,232,136,136,87,12,60,185,229,141,179,126,30,136,
9405100,130,233,231,59,12,228,34,66,52,243,141,167,118,158,153,80,73,9,201,151,
940630,252,153,106,210,146,118,72,150,76,184,247,228,203,86,148,152,123,246,
9407240,223,187,46,238,135,132,132,229,221,143,126,76,181,105,73,61,36,75,46,
9408236,123,242,101,171,74,76,61,251,120,111,221,151,119,67,226,65,178,243,199,
9409135,134,83,242,66,58,238,203,207,30,30,25,81,201,5,225,203,78,238,136,163,
9410208,92,59,50,242,232,138,62,0,2,38,163,19,255,255,224,142,80,192,0,20,31,
9411240,14,135,103,203,210,135,45,253,55,244,243,195,44,252,205,197,0,1,18,221,
941282,0,3,24,207,151,164,254,251,168,114,223,195,47,46,158,98,101,231,143,150,
9413158,29,55,242,104,68,79,62,94,147,251,238,161,203,127,12,188,186,121,157,
9414135,110,94,109,100,131,99,229,151,15,76,172,168,8,89,217,16,201,151,54,157,
9415217,104,114,223,195,47,46,154,114,243,102,68,19,158,92,59,27,73,6,205,203,
941646,95,89,91,74,0,3,17,225,203,47,108,187,186,69,241,211,46,238,122,119,238,
9417230,216,72,70,158,116,242,225,217,151,35,81,33,26,121,198,229,191,214,93,
9418205,69,0,1,134,105,231,23,199,76,187,185,233,197,179,43,73,32,154,242,249,
9419230,214,80,0,31,255,193,2,38,103,110,117,24,81,115,0,78,228,0,161,208,16,
9420237,24,121,207,239,186,135,45,252,50,242,233,229,188,144,221,60,232,114,
9421223,211,127,79,60,50,207,204,224,72,167,14,91,248,101,229,211,204,158,113,
9422119,117,219,151,150,28,91,50,184,144,40,95,224,0,15,248,64,4,20,78,129,5,
9423195,195,134,207,38,232,130,99,195,179,97,201,244,19,22,157,217,14,15,130,
9424135,254,0,48,125,60,224,242,229,135,200,9,1,255,12,2,162,136,112,2,112,80,
9425128,0,193,177,239,221,143,15,64,35,224,152,20,144,62,27,248,3,2,9,195,175,
942661,0,231,208,126,89,123,101,229,207,40,72,32,188,244,105,205,208,40,16,94,
9427123,52,227,202,22,136,39,61,252,186,6,18,13,207,134,205,56,242,134,175,65,
9428250,238,231,163,78,110,129,231,208,125,59,178,101,241,63,48,25,248,0,12,47,
9429102,30,125,36,238,201,151,196,252,192,103,255,255,240,92,189,178,242,242,8,
9430105,4,231,191,110,80,67,80,0,24,62,109,252,162,225,199,160,16,212,0,10,7,
9431183,15,0,67,80,0,56,54,109,59,58,101,228,8,106,0,9,6,229,151,39,92,121,66,
943215,192,0,97,124,178,228,235,143,45,45,57,244,116,8,63,255,255,10,39,248,0,
9433195,51,114,223,182,30,140,60,161,239,201,149,248,248,31,241,0,140,80,129,
9434202,10,49,128,10,35,1,6,199,163,15,40,61,32,9,10,199,163,15,40,123,242,101,
9435131,210,4,144,108,123,247,99,195,210,8,250,15,167,118,76,190,39,230,131,52,
9436133,236,195,207,164,157,217,50,248,159,154,12,212,0,6,27,179,126,60,59,50,
9437195,223,183,134,30,89,97,9,5,219,135,166,61,16,164,131,242,203,195,102,28,
9438121,97,145,6,231,151,15,44,122,33,201,5,231,179,78,60,177,8,130,243,225,
9439179,79,72,148,66,121,245,197,207,167,45,59,179,197,162,23,211,124,205,253,
9440242,242,135,135,158,87,240,68,122,111,153,191,30,29,153,102,111,239,151,
9441148,60,60,242,191,130,23,211,125,94,28,50,242,135,135,158,87,240,128,0,196,
9442122,111,153,191,30,29,153,106,240,225,151,148,60,60,242,191,132,0,6,9,211,
9443150,157,177,160,131,115,235,139,159,78,81,72,10,47,248,0,3,254,40,17,138,
944448,66,136,152,64,0,66,129,48,5,27,252,88,76,216,54,47,214,131,50,172,88,15,
9445253,255,255,255,255,255,255,240,153,178,103,95,173,6,101,88,176,0,0,0,0,0,
94460,0,0,67,168,15,255,0,0,0,0,0,0,17,26,19,233,201,169,38,180,91,242,103,70,
9447147,58,77,75,48,31,252,0,0,0,0,0,0,34,51,162,199,131,82,77,104,183,228,206,
9448141,38,116,154,150,96,127,248,0,0,0,0,0,0,0,15,248,192,70,40,0,0,0,0,0,0,0,
94490,3,10,44,68,9,216,8,20,49,130,15,211,124,109,62,50,228,95,36,55,166,248,
9450190,56,111,221,151,119,77,56,118,47,18,23,211,125,14,89,113,233,231,167,
9451126,230,18,5,31,252,0,224,188,48,242,231,148,116,144,58,181,33,143,127,64,
9452247,111,238,56,0,127,199,2,49,72,127,248,0,0,0,0,0,0,180,81,36,4,51,166,
9453248,152,122,101,167,211,150,157,217,201,2,0,3,12,233,190,166,157,185,105,
9454244,229,167,118,114,64,128,1,4,228,129,0,3,137,116,223,51,126,60,59,50,196,
9455195,211,45,62,156,180,238,206,72,16,0,72,151,77,243,55,227,195,179,45,77,
945659,114,211,233,203,78,236,228,129,0,5,10,73,2,0,12,21,18,4,0,28,82,35,32,
945780,74,8,62,124,189,42,105,219,148,148,16,188,249,122,70,235,179,101,156,
9458184,121,15,132,0,34,29,159,47,74,181,33,198,235,179,101,156,184,121,15,132,
94590,38,17,159,47,73,187,247,116,208,62,16,0,168,94,124,189,42,212,135,55,126,
9460238,154,7,194,0,23,7,207,151,164,76,61,50,143,132,0,50,21,159,47,74,181,33,
9461196,195,211,40,248,64,3,96,217,242,244,137,135,200,248,64,3,161,57,242,244,
9462171,82,28,76,62,71,194,0,31,8,207,151,164,141,253,121,115,31,8,0,132,47,62,
946394,149,106,67,145,191,175,46,99,225,0,17,133,103,203,210,110,157,221,122,
9464101,230,62,16,1,40,110,124,189,42,212,135,55,78,238,189,50,243,31,8,0,156,
946543,62,94,148,242,227,223,187,39,49,240,128,10,67,115,229,233,86,164,58,121,
9466113,239,221,147,152,248,64,5,97,249,242,244,155,167,102,205,60,242,227,223,
9467187,39,49,240,128,11,68,179,229,233,86,164,57,186,118,108,211,207,46,61,
9468251,178,115,31,8,0,188,71,62,94,149,52,237,203,235,126,236,179,243,102,231,
9469151,161,0,32,252,242,244,169,167,110,82,34,67,249,229,233,55,78,205,154,
9470121,229,199,191,118,78,100,37,0,24,137,115,203,210,173,72,115,116,236,217,
9471167,158,92,123,247,100,230,66,80,1,152,87,60,189,41,229,199,191,118,78,100,
947243,224,3,80,222,121,122,85,169,14,158,92,123,247,100,230,66,190,0,55,10,
9473231,151,164,221,59,186,244,203,204,133,252,0,114,27,207,47,74,181,33,205,
9474211,187,175,76,188,200,95,192,7,97,28,242,244,145,191,175,46,100,51,224,3,
9475208,190,121,122,85,169,14,70,254,188,185,144,207,128,15,193,249,229,233,19,
947615,76,164,37,0,32,133,115,203,210,173,72,113,48,244,202,66,80,2,24,71,60,
9477189,38,239,221,211,65,10,248,1,20,47,158,94,149,106,67,155,191,119,77,4,43,
9478224,4,112,190,121,122,70,235,179,101,156,184,121,16,191,128,18,67,185,229,
9479233,86,164,56,221,118,108,179,151,15,34,23,240,2,88,62,124,189,44,229,195,
9480200,124,32,4,208,126,121,122,89,203,135,145,9,64,9,194,145,254,0,0,255,144,
948124,100,130,14,0,16,176,2,192,129,11,33,12,1,168,193,108,96,186,48,95,32,0,
94820,0,0,0,0,0,0,56,38,95,25,113,189,18,9,211,47,62,143,100,20,95,0,20,159,
9483240,0,7,252,144,162,241,2,195,66,7,11,89,204,140,197,252,229,197,226,230,
9484115,3,16,69,19,64,5,43,252,0,9,255,40,16,188,33,49,123,97,217,23,151,45,
9485252,131,66,7,0,20,191,240,0,39,252,176,66,240,133,82,195,187,62,88,188,185,
9486111,228,26,16,56,0,166,127,128,1,63,230,2,23,132,58,150,92,217,121,101,221,
9487143,44,94,92,183,242,13,8,28,0,83,127,192,0,159,243,65,11,194,23,79,206,
9488238,152,124,69,229,203,127,32,208,129,192,5,59,252,0,9,255,56,16,188,33,53,
948960,240,203,23,151,45,252,131,66,7,0,20,255,240,0,39,252,240,66,240,132,85,
9490165,38,47,46,91,249,6,132,14,0,31,255,228,64,98,192,64,5,191,10,139,20,87,
9491105,130,76,156,197,132,4,0,38,187,27,187,85,81,104,28,201,204,160,31,243,
949223,33,127,125,28,247,193,102,79,142,202,44,3,255,113,84,118,82,184,47,232,
949352,201,241,216,176,139,0,255,111,45,236,84,155,148,58,5,66,76,4,0,146,31,
9494181,68,66,209,136,61,58,52,170,49,190,202,1,255,53,4,243,51,249,222,108,22,
9495157,26,85,25,64,63,246,160,158,102,127,59,205,74,7,135,23,53,2,65,48,227,
9496223,205,64,160,0,48,76,60,244,238,80,40,0,20,19,15,76,59,148,10,0,7,5,195,
9497211,14,230,74,72,130,99,203,167,98,129,64,1,32,120,247,243,80,40,0,44,15,
949847,142,10,5,0,6,130,230,217,191,127,37,2,128,3,192,246,111,206,160,80,0,
9499136,30,220,62,19,151,160,123,116,238,79,94,129,240,223,221,73,32,0,48,110,
950088,119,100,223,181,68,16,94,91,250,238,200,160,80,0,152,31,61,59,148,10,0,
950121,4,231,199,151,69,2,128,5,192,250,97,220,160,80,0,192,127,255,128,20,23,
9502134,30,92,242,164,34,19,207,167,45,59,179,233,205,229,37,129,127,255,0,0,
9503191,255,128,0,63,255,197,131,246,203,203,158,157,251,160,32,98,140,0,0,0,0,
95040,3,166,156,30,53,32,249,165,131,76,223,159,62,94,70,172,114,16,176,144,60,
950556,250,19,18,5,159,25,89,32,121,180,238,42,30,129,229,221,140,164,122,7,
9506147,46,50,129,232,62,61,251,120,97,199,208,156,129,83,127,0,50,250,69,3,
9507252,131,32,248,250,242,229,151,119,72,240,3,254,148,0,2,168,254,0,0,255,
9508167,0,33,68,88,32,0,33,64,176,2,170,254,0,0,255,169,0,33,69,220,32,0,33,67,
9509184,2,172,254,0,0,255,171,8,137,144,128,0,0,0,0,0,0,0,68,73,4,195,187,126,
9510226,8,4,178,16,41,164,32,147,7,136,52,193,240,0,18,17,48,124,0,8,133,76,31,
95110,3,33,147,7,192,1,8,116,193,240,0,82,127,255,132,47,65,11,137,191,174,45,
9512153,98,242,229,191,144,105,4,95,47,46,91,249,32,211,185,6,94,92,183,242,65,
9513163,14,236,155,52,238,206,0,85,255,192,6,13,167,157,109,57,123,136,144,31,
9514245,192,3,5,231,179,78,60,163,9,0,2,10,199,248,0,3,254,192,4,32,249,242,
9515244,147,187,163,129,116,128,24,66,51,229,233,87,78,238,142,5,210,0,65,8,
9516207,151,164,157,221,24,182,23,72,1,140,39,62,94,149,116,238,232,197,176,
9517186,64,8,97,25,242,244,147,187,163,54,66,233,0,50,132,231,203,210,174,157,
9518221,25,178,23,72,1,20,43,62,94,145,182,111,195,209,155,33,116,128,17,194,
9519179,229,233,27,102,252,61,27,52,23,72,1,36,31,158,94,146,119,116,112,50,
9520208,3,8,71,60,189,42,233,221,209,192,203,64,8,33,28,242,244,147,187,163,22,
9521195,45,0,49,132,243,203,210,174,157,221,24,182,25,104,1,12,35,158,94,146,
9522119,116,102,200,101,160,6,80,158,121,122,85,211,187,163,54,67,45,0,34,133,
9523115,203,210,54,205,248,122,51,100,50,208,2,56,87,60,189,35,108,223,135,163,
9524102,131,45,0,36,7,255,248,1,11,50,136,132,115,235,139,15,46,88,124,140,36,
95250,4,43,79,224,139,16,15,252,0,0,0,0,0,0,0,101,253,152,0,5,109,252,17,98,1,
9526255,128,0,0,0,0,0,0,12,191,181,0,0,174,63,130,44,64,63,240,0,0,0,0,0,0,1,
9527151,246,224,0,21,215,240,69,136,8,0,0,0,0,0,0,0,0,50,254,228,0,2,188,254,8,
9528177,1,0,0,0,0,0,0,0,0,6,95,221,128,0,87,223,193,22,32,32,8,0,0,0,0,0,0,0,
9529203,251,208,0,11,3,248,34,196,4,1,0,0,0,0,0,0,0,25,127,126,0,1,97,127,4,88,
9530128,128,32,0,0,0,0,0,0,3,47,240,64,0,44,79,224,139,16,16,8,0,0,0,0,0,0,0,
9531101,254,24,0,5,141,252,1,96,216,247,238,199,135,162,162,33,90,121,197,221,
9532143,126,77,59,179,172,146,17,167,156,46,185,179,101,228,176,65,89,77,16,
9533124,123,246,240,195,203,40,162,64,0,193,255,138,5,144,158,89,112,228,171,
953439,119,71,2,232,132,114,203,135,36,157,221,28,11,164,0,66,25,203,46,28,149,
9535100,238,232,197,180,200,162,233,0,1,134,114,203,135,37,89,59,186,49,109,10,
953640,186,64,2,97,124,178,225,201,39,119,70,45,166,69,23,72,0,140,47,150,92,
953757,36,238,232,197,180,40,162,233,0,25,134,114,203,135,37,89,59,186,51,101,
953850,40,186,64,0,161,156,178,225,201,86,78,238,140,217,66,138,46,144,0,168,
953995,44,184,114,73,221,209,155,41,145,69,210,0,37,11,229,151,14,73,59,186,51,
9540101,10,40,186,64,6,161,124,178,225,201,27,102,252,61,38,69,23,72,0,28,47,
9541150,92,57,35,108,223,135,164,40,162,233,0,11,134,114,203,135,36,77,253,113,
9542108,203,50,40,186,64,1,33,156,178,225,201,19,127,92,91,50,194,138,46,144,0,
9543200,87,44,184,114,85,147,187,164,200,162,237,0,5,133,114,203,135,37,89,59,
9544186,66,138,46,208,0,216,79,44,184,114,73,221,210,100,81,118,128,10,194,121,
9545101,195,146,78,238,144,162,139,180,0,118,21,223,150,158,153,106,201,221,
9546209,192,203,33,61,249,105,233,150,78,238,142,6,90,0,33,13,239,203,79,76,
9547181,100,238,232,197,180,200,163,45,0,1,134,247,229,167,166,90,178,119,116,
954898,218,20,81,150,128,4,195,59,242,211,211,44,157,221,24,182,153,20,101,160,
95492,48,206,252,180,244,203,39,119,70,45,161,69,25,104,0,204,55,191,45,61,50,
9550213,147,187,163,54,83,34,140,180,0,10,27,223,150,158,153,106,201,221,209,
9551155,40,81,70,90,0,21,12,239,203,79,76,178,119,116,102,202,100,81,150,128,9,
955267,59,242,211,211,44,157,221,25,178,133,20,101,160,3,80,206,252,180,244,
9553203,27,102,252,61,38,69,25,104,0,28,51,191,45,61,50,198,217,191,15,72,81,
955470,90,0,23,13,239,203,79,76,177,55,245,197,179,44,200,163,45,0,4,134,247,
9555229,167,166,88,155,250,226,217,150,20,81,150,128,6,66,251,242,211,211,45,
955689,59,186,76,138,51,16,0,88,95,126,90,122,101,171,39,119,72,81,70,98,0,27,
955710,239,203,79,76,178,119,116,153,20,102,32,2,176,174,252,180,244,203,39,
9558119,72,81,70,98,0,58,40,173,176,82,90,4,19,54,157,155,21,217,6,203,199,174,
955929,156,197,9,7,199,191,111,12,60,178,138,20,0,6,9,143,127,15,42,208,130,
9560243,217,167,30,81,132,65,123,242,211,211,42,228,0,
7c673cae 9561};
11fdf7f2
TL
9562#elif defined(DUK_USE_DOUBLE_ME)
9563DUK_INTERNAL const duk_uint8_t duk_builtins_data[3833] = {
9564105,195,75,32,3,148,52,154,248,9,26,13,128,112,105,0,240,22,20,26,95,124,6,
9565152,52,137,0,120,99,74,239,129,18,70,241,191,2,98,13,79,32,42,88,210,90,2,
9566240,1,50,141,37,168,76,94,216,118,69,229,203,127,44,0,84,163,73,106,21,75,
956714,236,249,98,242,229,191,150,0,46,81,164,181,14,165,151,54,94,89,119,99,
9568203,23,151,45,252,176,1,146,141,37,168,93,63,59,186,97,241,23,151,45,252,
9569176,1,178,141,37,168,77,79,60,50,197,229,203,127,44,0,116,163,73,106,17,86,
9570148,152,188,185,111,229,128,15,148,129,198,137,36,58,166,142,91,251,212,
9571243,195,44,94,92,183,242,13,79,8,45,14,91,252,121,148,52,199,120,63,72,105,
957221,240,118,128,210,237,224,245,17,165,43,224,211,55,231,207,151,148,161,70,
9573145,0,31,40,107,26,2,18,138,26,228,192,142,0,16,161,174,76,9,74,26,228,192,
9574158,0,8,161,174,76,10,96,2,42,26,228,192,174,0,26,161,174,76,11,96,3,74,26,
9575228,192,190,0,44,161,174,76,12,96,3,202,26,228,192,206,0,70,161,169,84,14,
9576202,3,255,254,32,234,0,0,7,195,248,0,0,0,0,119,0,0,3,193,252,0,0,0,0,57,
9577136,1,152,32,16,194,0,166,24,6,49,0,57,138,2,12,96,18,99,128,163,32,5,153,
957840,76,94,216,118,69,229,203,127,35,41,10,165,135,118,124,177,121,114,223,
9579200,203,67,169,101,205,151,150,93,216,242,197,229,203,127,35,49,11,167,231,
9580119,76,62,34,242,229,191,145,154,132,212,243,195,44,94,92,183,242,51,144,
9581138,180,164,197,229,203,127,35,60,6,26,0,52,208,193,226,117,215,211,15,12,
9582166,146,11,67,150,255,30,77,24,58,113,64,243,92,8,27,0,68,217,130,70,212,
958319,54,224,161,185,5,77,216,44,111,65,115,126,12,28,16,100,225,156,16,32,18,
958417,195,15,46,121,100,238,232,136,136,87,12,60,185,229,141,179,126,30,136,
9585100,130,233,231,59,12,228,34,66,52,243,141,167,118,158,153,80,73,9,201,151,
958630,252,153,106,210,146,118,72,150,76,184,247,228,203,86,148,152,123,246,
9587240,223,187,46,238,135,132,132,229,221,143,126,76,181,105,73,61,36,75,46,
9588236,123,242,101,171,74,76,61,251,120,111,221,151,119,67,226,65,178,243,199,
9589135,134,83,242,66,58,238,203,207,30,30,25,81,201,5,225,203,78,238,136,163,
9590208,92,59,50,242,232,138,62,0,2,38,163,19,255,255,224,142,80,192,0,20,31,
9591240,14,135,103,203,210,135,45,253,55,244,243,195,44,252,205,197,0,1,18,221,
959282,0,3,24,207,151,164,254,251,168,114,223,195,47,46,158,98,101,231,143,150,
9593158,29,55,242,104,68,79,62,94,147,251,238,161,203,127,12,188,186,121,157,
9594135,110,94,109,100,131,99,229,151,15,76,172,168,8,89,217,16,201,151,54,157,
9595217,104,114,223,195,47,46,154,114,243,102,68,19,158,92,59,27,73,6,205,203,
959646,95,89,91,74,0,3,17,225,203,47,108,187,186,69,241,211,46,238,122,119,238,
9597230,216,72,70,158,116,242,225,217,151,35,81,33,26,121,198,229,191,214,93,
9598205,69,0,1,134,105,231,23,199,76,187,185,233,197,179,43,73,32,154,242,249,
9599230,214,80,0,31,255,193,2,38,103,110,117,24,81,115,0,78,228,0,161,208,16,
9600237,24,121,207,239,186,135,45,252,50,242,233,229,188,144,221,60,232,114,
9601223,211,127,79,60,50,207,204,224,72,167,14,91,248,101,229,211,204,158,113,
9602119,117,219,151,150,28,91,50,184,144,40,95,224,0,15,248,64,4,20,78,129,5,
9603195,195,134,207,38,232,130,99,195,179,97,201,244,19,22,157,217,14,15,130,
9604135,254,0,48,125,60,224,242,229,135,200,9,1,255,12,2,162,136,112,2,112,80,
9605128,0,193,177,239,221,143,15,64,35,224,152,20,144,62,27,248,3,2,9,195,175,
960661,0,231,208,126,89,123,101,229,207,40,72,32,188,244,105,205,208,40,16,94,
9607123,52,227,202,22,136,39,61,252,186,6,18,13,207,134,205,56,242,134,175,65,
9608250,238,231,163,78,110,129,231,208,125,59,178,101,241,63,48,25,248,0,12,47,
9609102,30,125,36,238,201,151,196,252,192,103,255,255,240,92,189,178,242,242,8,
9610105,4,231,191,110,80,67,80,0,24,62,109,252,162,225,199,160,16,212,0,10,7,
9611183,15,0,67,80,0,56,54,109,59,58,101,228,8,106,0,9,6,229,151,39,92,121,66,
961215,192,0,97,124,178,228,235,143,45,45,57,244,116,8,63,255,255,10,39,248,0,
9613195,51,114,223,182,30,140,60,161,239,201,149,248,248,31,241,0,140,80,129,
9614202,10,49,128,10,35,1,6,199,163,15,40,61,32,9,10,199,163,15,40,123,242,101,
9615131,210,4,144,108,123,247,99,195,210,8,250,15,167,118,76,190,39,230,131,52,
9616133,236,195,207,164,157,217,50,248,159,154,12,212,0,6,27,179,126,60,59,50,
9617195,223,183,134,30,89,97,9,5,219,135,166,61,16,164,131,242,203,195,102,28,
9618121,97,145,6,231,151,15,44,122,33,201,5,231,179,78,60,177,8,130,243,225,
9619179,79,72,148,66,121,245,197,207,167,45,59,179,197,162,23,211,124,205,253,
9620242,242,135,135,158,87,240,68,122,111,153,191,30,29,153,102,111,239,151,
9621148,60,60,242,191,130,23,211,125,94,28,50,242,135,135,158,87,240,128,0,196,
9622122,111,153,191,30,29,153,106,240,225,151,148,60,60,242,191,132,0,6,9,211,
9623150,157,177,160,131,115,235,139,159,78,81,72,10,47,248,0,3,254,40,17,138,
962448,66,136,152,64,0,66,129,48,5,27,252,88,76,216,54,47,214,131,50,172,88,31,
9625255,253,239,255,255,255,255,240,153,178,103,95,173,6,101,88,176,0,0,0,0,0,
962664,0,0,3,168,0,0,31,15,224,0,0,0,17,26,19,233,201,169,38,180,91,242,103,70,
9627147,58,77,75,48,0,0,60,31,192,0,0,0,34,51,162,199,131,82,77,104,183,228,
9628206,141,38,116,154,150,96,0,0,120,127,128,0,0,0,0,15,248,192,70,40,0,0,0,0,
96290,0,0,0,3,10,44,68,9,216,8,20,49,130,15,211,124,109,62,50,228,95,36,55,166,
9630248,190,56,111,221,151,119,77,56,118,47,18,23,211,125,14,89,113,233,231,
9631167,126,230,18,5,31,252,0,224,188,48,242,231,148,116,144,58,181,33,143,127,
963264,247,111,238,56,0,127,199,2,49,72,0,0,248,127,0,0,0,0,180,81,36,4,51,166,
9633248,152,122,101,167,211,150,157,217,201,2,0,3,12,233,190,166,157,185,105,
9634244,229,167,118,114,64,128,1,4,228,129,0,3,137,116,223,51,126,60,59,50,196,
9635195,211,45,62,156,180,238,206,72,16,0,72,151,77,243,55,227,195,179,45,77,
963659,114,211,233,203,78,236,228,129,0,5,10,73,2,0,12,21,18,4,0,28,82,35,32,
963780,74,8,62,124,189,42,105,219,148,148,16,188,249,122,70,235,179,101,156,
9638184,121,15,132,0,34,29,159,47,74,181,33,198,235,179,101,156,184,121,15,132,
96390,38,17,159,47,73,187,247,116,208,62,16,0,168,94,124,189,42,212,135,55,126,
9640238,154,7,194,0,23,7,207,151,164,76,61,50,143,132,0,50,21,159,47,74,181,33,
9641196,195,211,40,248,64,3,96,217,242,244,137,135,200,248,64,3,161,57,242,244,
9642171,82,28,76,62,71,194,0,31,8,207,151,164,141,253,121,115,31,8,0,132,47,62,
964394,149,106,67,145,191,175,46,99,225,0,17,133,103,203,210,110,157,221,122,
9644101,230,62,16,1,40,110,124,189,42,212,135,55,78,238,189,50,243,31,8,0,156,
964543,62,94,148,242,227,223,187,39,49,240,128,10,67,115,229,233,86,164,58,121,
9646113,239,221,147,152,248,64,5,97,249,242,244,155,167,102,205,60,242,227,223,
9647187,39,49,240,128,11,68,179,229,233,86,164,57,186,118,108,211,207,46,61,
9648251,178,115,31,8,0,188,71,62,94,149,52,237,203,235,126,236,179,243,102,231,
9649151,161,0,32,252,242,244,169,167,110,82,34,67,249,229,233,55,78,205,154,
9650121,229,199,191,118,78,100,37,0,24,137,115,203,210,173,72,115,116,236,217,
9651167,158,92,123,247,100,230,66,80,1,152,87,60,189,41,229,199,191,118,78,100,
965243,224,3,80,222,121,122,85,169,14,158,92,123,247,100,230,66,190,0,55,10,
9653231,151,164,221,59,186,244,203,204,133,252,0,114,27,207,47,74,181,33,205,
9654211,187,175,76,188,200,95,192,7,97,28,242,244,145,191,175,46,100,51,224,3,
9655208,190,121,122,85,169,14,70,254,188,185,144,207,128,15,193,249,229,233,19,
965615,76,164,37,0,32,133,115,203,210,173,72,113,48,244,202,66,80,2,24,71,60,
9657189,38,239,221,211,65,10,248,1,20,47,158,94,149,106,67,155,191,119,77,4,43,
9658224,4,112,190,121,122,70,235,179,101,156,184,121,16,191,128,18,67,185,229,
9659233,86,164,56,221,118,108,179,151,15,34,23,240,2,88,62,124,189,44,229,195,
9660200,124,32,4,208,126,121,122,89,203,135,145,9,64,9,194,145,254,0,0,255,144,
966124,100,130,14,0,16,176,2,192,129,11,33,12,1,168,193,108,96,186,48,95,32,0,
96620,0,0,0,0,0,0,56,38,95,25,113,189,18,9,211,47,62,143,100,20,95,0,20,159,
9663240,0,7,252,144,162,241,2,195,66,7,11,89,204,140,197,252,229,197,226,230,
9664115,3,16,69,19,64,5,43,252,0,9,255,40,16,188,33,49,123,97,217,23,151,45,
9665252,131,66,7,0,20,191,240,0,39,252,176,66,240,133,82,195,187,62,88,188,185,
9666111,228,26,16,56,0,166,127,128,1,63,230,2,23,132,58,150,92,217,121,101,221,
9667143,44,94,92,183,242,13,8,28,0,83,127,192,0,159,243,65,11,194,23,79,206,
9668238,152,124,69,229,203,127,32,208,129,192,5,59,252,0,9,255,56,16,188,33,53,
966960,240,203,23,151,45,252,131,66,7,0,20,255,240,0,39,252,240,66,240,132,85,
9670165,38,47,46,91,249,6,132,14,0,31,255,228,64,98,192,10,191,5,64,105,87,20,
9671139,130,76,156,197,132,11,22,176,36,1,101,91,91,184,28,201,204,160,33,23,
9672115,31,247,156,253,127,65,102,79,142,202,44,4,113,95,115,255,232,34,182,88,
967352,201,241,216,176,139,1,239,47,108,252,59,148,152,86,5,66,76,15,178,16,
9674148,1,130,212,69,72,61,58,52,170,49,190,202,4,245,7,49,254,105,219,251,52,
967522,157,26,85,25,64,158,160,246,63,205,59,127,102,74,7,135,23,53,2,65,48,
9676227,223,205,64,160,0,48,76,60,244,238,80,40,0,20,19,15,76,59,148,10,0,7,5,
9677195,211,14,230,74,72,130,99,203,167,98,129,64,1,32,120,247,243,80,40,0,44,
967815,47,142,10,5,0,6,130,230,217,191,127,37,2,128,3,192,246,111,206,160,80,0,
9679136,30,220,62,19,151,160,123,116,238,79,94,129,240,223,221,73,32,0,48,110,
968088,119,100,223,181,68,16,94,91,250,238,200,160,80,0,152,31,61,59,148,10,0,
968121,4,231,199,151,69,2,128,5,192,250,97,220,160,80,0,192,127,255,128,20,23,
9682134,30,92,242,164,34,19,207,167,45,59,179,233,205,229,37,129,127,255,0,0,
9683191,255,128,0,63,255,197,131,246,203,203,158,157,251,160,0,12,98,160,0,0,0,
96840,3,166,156,30,53,32,249,165,131,76,223,159,62,94,70,172,114,16,176,144,60,
968556,250,19,18,5,159,25,89,32,121,180,238,42,30,129,229,221,140,164,122,7,
9686147,46,50,129,232,62,61,251,120,97,199,208,156,129,83,127,0,50,250,69,3,
9687252,131,32,248,250,242,229,151,119,72,240,3,254,148,0,2,168,254,0,0,255,
9688167,0,33,68,88,32,0,33,64,176,2,170,254,0,0,255,169,0,33,69,220,32,0,33,67,
9689184,2,172,254,0,0,255,171,8,137,144,0,0,0,128,0,0,0,0,68,73,4,195,187,126,
9690226,8,4,178,16,41,164,32,147,7,136,52,193,240,0,18,17,48,124,0,8,133,76,31,
96910,3,33,147,7,192,1,8,116,193,240,0,82,127,255,132,47,65,11,137,191,174,45,
9692153,98,242,229,191,144,105,4,95,47,46,91,249,32,211,185,6,94,92,183,242,65,
9693163,14,236,155,52,238,206,0,85,255,192,6,13,167,157,109,57,123,136,144,31,
9694245,192,3,5,231,179,78,60,163,9,0,2,10,199,248,0,3,254,192,4,32,249,242,
9695244,147,187,163,129,116,128,24,66,51,229,233,87,78,238,142,5,210,0,65,8,
9696207,151,164,157,221,24,182,23,72,1,140,39,62,94,149,116,238,232,197,176,
9697186,64,8,97,25,242,244,147,187,163,54,66,233,0,50,132,231,203,210,174,157,
9698221,25,178,23,72,1,20,43,62,94,145,182,111,195,209,155,33,116,128,17,194,
9699179,229,233,27,102,252,61,27,52,23,72,1,36,31,158,94,146,119,116,112,50,
9700208,3,8,71,60,189,42,233,221,209,192,203,64,8,33,28,242,244,147,187,163,22,
9701195,45,0,49,132,243,203,210,174,157,221,24,182,25,104,1,12,35,158,94,146,
9702119,116,102,200,101,160,6,80,158,121,122,85,211,187,163,54,67,45,0,34,133,
9703115,203,210,54,205,248,122,51,100,50,208,2,56,87,60,189,35,108,223,135,163,
9704102,131,45,0,36,7,255,248,1,11,50,136,132,115,235,139,15,46,88,124,140,36,
97050,4,43,79,224,139,16,0,0,60,15,192,0,0,0,0,101,253,152,0,5,109,252,17,98,0,
97060,7,129,248,0,0,0,0,12,191,181,0,0,174,63,130,44,64,0,0,240,63,0,0,0,0,1,
9707151,246,224,0,21,215,240,69,136,0,0,0,8,0,0,0,0,0,50,254,228,0,2,188,254,8,
9708177,0,0,0,1,0,0,0,0,0,6,95,221,128,0,87,223,193,22,32,0,0,8,32,0,0,0,0,0,
9709203,251,208,0,11,3,248,34,196,0,0,1,4,0,0,0,0,0,25,127,126,0,1,97,127,4,88,
9710128,0,0,32,128,0,0,0,0,3,47,240,64,0,44,79,224,139,16,0,0,8,16,0,0,0,0,0,
9711101,254,24,0,5,141,252,1,96,216,247,238,199,135,162,162,33,90,121,197,221,
9712143,126,77,59,179,172,146,17,167,156,46,185,179,101,228,176,65,89,77,16,
9713124,123,246,240,195,203,40,162,64,0,193,255,138,5,144,158,89,112,228,171,
971439,119,71,2,232,132,114,203,135,36,157,221,28,11,164,0,66,25,203,46,28,149,
9715100,238,232,197,180,200,162,233,0,1,134,114,203,135,37,89,59,186,49,109,10,
971640,186,64,2,97,124,178,225,201,39,119,70,45,166,69,23,72,0,140,47,150,92,
971757,36,238,232,197,180,40,162,233,0,25,134,114,203,135,37,89,59,186,51,101,
971850,40,186,64,0,161,156,178,225,201,86,78,238,140,217,66,138,46,144,0,168,
971995,44,184,114,73,221,209,155,41,145,69,210,0,37,11,229,151,14,73,59,186,51,
9720101,10,40,186,64,6,161,124,178,225,201,27,102,252,61,38,69,23,72,0,28,47,
9721150,92,57,35,108,223,135,164,40,162,233,0,11,134,114,203,135,36,77,253,113,
9722108,203,50,40,186,64,1,33,156,178,225,201,19,127,92,91,50,194,138,46,144,0,
9723200,87,44,184,114,85,147,187,164,200,162,237,0,5,133,114,203,135,37,89,59,
9724186,66,138,46,208,0,216,79,44,184,114,73,221,210,100,81,118,128,10,194,121,
9725101,195,146,78,238,144,162,139,180,0,118,21,223,150,158,153,106,201,221,
9726209,192,203,33,61,249,105,233,150,78,238,142,6,90,0,33,13,239,203,79,76,
9727181,100,238,232,197,180,200,163,45,0,1,134,247,229,167,166,90,178,119,116,
972898,218,20,81,150,128,4,195,59,242,211,211,44,157,221,24,182,153,20,101,160,
97292,48,206,252,180,244,203,39,119,70,45,161,69,25,104,0,204,55,191,45,61,50,
9730213,147,187,163,54,83,34,140,180,0,10,27,223,150,158,153,106,201,221,209,
9731155,40,81,70,90,0,21,12,239,203,79,76,178,119,116,102,202,100,81,150,128,9,
973267,59,242,211,211,44,157,221,25,178,133,20,101,160,3,80,206,252,180,244,
9733203,27,102,252,61,38,69,25,104,0,28,51,191,45,61,50,198,217,191,15,72,81,
973470,90,0,23,13,239,203,79,76,177,55,245,197,179,44,200,163,45,0,4,134,247,
9735229,167,166,88,155,250,226,217,150,20,81,150,128,6,66,251,242,211,211,45,
973689,59,186,76,138,51,16,0,88,95,126,90,122,101,171,39,119,72,81,70,98,0,27,
973710,239,203,79,76,178,119,116,153,20,102,32,2,176,174,252,180,244,203,39,
9738119,72,81,70,98,0,58,40,173,176,82,90,4,19,54,157,155,21,217,6,203,199,174,
973929,156,197,9,7,199,191,111,12,60,178,138,20,0,6,9,143,127,15,42,208,130,
9740243,217,167,30,81,132,65,123,242,211,211,42,228,0,
7c673cae 9741};
7c673cae
FG
9742#else
9743#error invalid endianness defines
9744#endif
11fdf7f2 9745#endif /* DUK_USE_ROM_OBJECTS */
7c673cae
FG
9746/*
9747 * Error, fatal, and panic handling.
9748 */
9749
9750/* include removed: duk_internal.h */
9751
9752#define DUK__ERRFMT_BUFSIZE 256 /* size for formatting buffers */
9753
11fdf7f2 9754#if defined(DUK_USE_VERBOSE_ERRORS)
7c673cae 9755
11fdf7f2 9756DUK_INTERNAL void duk_err_handle_error_fmt(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *fmt, ...) {
7c673cae
FG
9757 va_list ap;
9758 char msg[DUK__ERRFMT_BUFSIZE];
9759 va_start(ap, fmt);
9760 (void) DUK_VSNPRINTF(msg, sizeof(msg), fmt, ap);
9761 msg[sizeof(msg) - 1] = (char) 0;
11fdf7f2 9762 duk_err_create_and_throw(thr, (duk_errcode_t) (line_and_code >> 24), msg, filename, (duk_int_t) (line_and_code & 0x00ffffffL));
7c673cae
FG
9763 va_end(ap); /* dead code, but ensures portability (see Linux man page notes) */
9764}
7c673cae 9765
11fdf7f2
TL
9766DUK_INTERNAL void duk_err_handle_error(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *msg) {
9767 duk_err_create_and_throw(thr, (duk_errcode_t) (line_and_code >> 24), msg, filename, (duk_int_t) (line_and_code & 0x00ffffffL));
7c673cae 9768}
7c673cae
FG
9769
9770#else /* DUK_USE_VERBOSE_ERRORS */
9771
7c673cae
FG
9772DUK_INTERNAL void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code) {
9773 duk_err_create_and_throw(thr, code);
9774}
9775
11fdf7f2 9776#endif /* DUK_USE_VERBOSE_ERRORS */
7c673cae 9777
11fdf7f2
TL
9778/*
9779 * Error throwing helpers
9780 */
7c673cae 9781
11fdf7f2
TL
9782#if defined(DUK_USE_VERBOSE_ERRORS)
9783#if defined(DUK_USE_PARANOID_ERRORS)
9784DUK_INTERNAL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index, const char *expect_name) {
9785 DUK_ERROR_RAW_FMT3(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)",
9786 expect_name, duk_get_type_name((duk_context *) thr, index), (long) index);
9787}
9788#else
9789DUK_INTERNAL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index, const char *expect_name) {
9790 DUK_ERROR_RAW_FMT3(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)",
9791 expect_name, duk_push_string_readable((duk_context *) thr, index), (long) index);
9792}
9793#endif
9794DUK_INTERNAL void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
9795 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, message);
9796}
9797DUK_INTERNAL void duk_err_api_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index) {
9798 DUK_ERROR_RAW_FMT1(thr, filename, linenumber, DUK_ERR_API_ERROR, "invalid stack index %ld", (long) (index));
9799}
9800DUK_INTERNAL void duk_err_api(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
9801 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_API_ERROR, message);
9802}
9803DUK_INTERNAL void duk_err_unimplemented_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
9804 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_UNIMPLEMENTED_ERROR, DUK_STR_UNIMPLEMENTED);
9805}
9806#if !defined(DUK_USE_BYTECODE_DUMP_SUPPORT)
9807DUK_INTERNAL void duk_err_unsupported_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
9808 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_UNSUPPORTED_ERROR, DUK_STR_UNSUPPORTED);
9809}
9810#endif
9811DUK_INTERNAL void duk_err_internal_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
9812 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_INTERNAL_ERROR, DUK_STR_INTERNAL_ERROR);
9813}
9814DUK_INTERNAL void duk_err_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
9815 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_INTERNAL_ERROR, message);
9816}
9817DUK_INTERNAL void duk_err_alloc(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
9818 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ALLOC_ERROR, message);
9819}
9820#else
9821/* The file/line arguments are NULL and 0, they're ignored by DUK_ERROR_RAW()
9822 * when non-verbose errors are used.
9823 */
9824DUK_INTERNAL void duk_err_type(duk_hthread *thr) {
9825 DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_TYPE_ERROR, NULL);
9826}
9827DUK_INTERNAL void duk_err_api(duk_hthread *thr) {
9828 DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_API_ERROR, NULL);
9829}
9830DUK_INTERNAL void duk_err_range(duk_hthread *thr) {
9831 DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_RANGE_ERROR, NULL);
9832}
9833DUK_INTERNAL void duk_err_syntax(duk_hthread *thr) {
9834 DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_SYNTAX_ERROR, NULL);
9835}
9836DUK_INTERNAL void duk_err_unimplemented(duk_hthread *thr) {
9837 DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_UNIMPLEMENTED_ERROR, NULL);
9838}
9839DUK_INTERNAL void duk_err_unsupported(duk_hthread *thr) {
9840 DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_UNSUPPORTED_ERROR, NULL);
9841}
9842DUK_INTERNAL void duk_err_internal(duk_hthread *thr) {
9843 DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_INTERNAL_ERROR, NULL);
9844}
9845DUK_INTERNAL void duk_err_alloc(duk_hthread *thr) {
9846 DUK_ERROR_RAW(thr, NULL, thr, DUK_ERR_ALLOC_ERROR, NULL);
9847}
9848#endif
7c673cae
FG
9849
9850/*
9851 * Default fatal error handler
9852 */
9853
9854DUK_INTERNAL void duk_default_fatal_handler(duk_context *ctx, duk_errcode_t code, const char *msg) {
9855 DUK_UNREF(ctx);
11fdf7f2 9856#if defined(DUK_USE_FILE_IO)
7c673cae
FG
9857 DUK_FPRINTF(DUK_STDERR, "FATAL %ld: %s\n", (long) code, (const char *) (msg ? msg : "null"));
9858 DUK_FFLUSH(DUK_STDERR);
9859#else
9860 /* omit print */
9861#endif
9862 DUK_D(DUK_DPRINT("default fatal handler called, code %ld -> calling DUK_PANIC()", (long) code));
9863 DUK_PANIC(code, msg);
9864 DUK_UNREACHABLE();
9865}
9866
9867/*
9868 * Default panic handler
9869 */
9870
9871#if !defined(DUK_USE_PANIC_HANDLER)
9872DUK_INTERNAL void duk_default_panic_handler(duk_errcode_t code, const char *msg) {
11fdf7f2 9873#if defined(DUK_USE_FILE_IO)
7c673cae
FG
9874 DUK_FPRINTF(DUK_STDERR, "PANIC %ld: %s ("
9875#if defined(DUK_USE_PANIC_ABORT)
9876 "calling abort"
9877#elif defined(DUK_USE_PANIC_EXIT)
9878 "calling exit"
9879#elif defined(DUK_USE_PANIC_SEGFAULT)
9880 "segfaulting on purpose"
9881#else
9882#error no DUK_USE_PANIC_xxx macro defined
9883#endif
9884 ")\n", (long) code, (const char *) (msg ? msg : "null"));
9885 DUK_FFLUSH(DUK_STDERR);
9886#else
9887 /* omit print */
9888 DUK_UNREF(code);
9889 DUK_UNREF(msg);
9890#endif
9891
9892#if defined(DUK_USE_PANIC_ABORT)
9893 DUK_ABORT();
9894#elif defined(DUK_USE_PANIC_EXIT)
9895 DUK_EXIT(-1);
9896#elif defined(DUK_USE_PANIC_SEGFAULT)
9897 /* exit() afterwards to satisfy "noreturn" */
9898 DUK_CAUSE_SEGFAULT(); /* SCANBUILD: "Dereference of null pointer", normal */
9899 DUK_EXIT(-1);
9900#else
9901#error no DUK_USE_PANIC_xxx macro defined
9902#endif
9903
9904 DUK_UNREACHABLE();
9905}
9906#endif /* !DUK_USE_PANIC_HANDLER */
9907
9908#undef DUK__ERRFMT_BUFSIZE
7c673cae
FG
9909/*
9910 * Various Unicode help functions for character classification predicates,
9911 * case conversion, decoding, etc.
9912 */
9913
9914/* include removed: duk_internal.h */
9915
11fdf7f2
TL
9916/*
9917 * Fast path tables
9918 */
9919
9920#if defined(DUK_USE_IDCHAR_FASTPATH)
9921DUK_INTERNAL const duk_int8_t duk_is_idchar_tab[128] = {
9922 /* 0: not IdentifierStart or IdentifierPart
9923 * 1: IdentifierStart and IdentifierPart
9924 * -1: IdentifierPart only
9925 */
9926 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00...0x0f */
9927 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10...0x1f */
9928 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20...0x2f */
9929 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, /* 0x30...0x3f */
9930 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40...0x4f */
9931 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 0x50...0x5f */
9932 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60...0x6f */
9933 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 /* 0x70...0x7f */
9934};
9935#endif
9936
7c673cae
FG
9937/*
9938 * XUTF-8 and CESU-8 encoding/decoding
9939 */
9940
9941DUK_INTERNAL duk_small_int_t duk_unicode_get_xutf8_length(duk_ucodepoint_t cp) {
9942 duk_uint_fast32_t x = (duk_uint_fast32_t) cp;
9943 if (x < 0x80UL) {
9944 /* 7 bits */
9945 return 1;
9946 } else if (x < 0x800UL) {
9947 /* 11 bits */
9948 return 2;
9949 } else if (x < 0x10000UL) {
9950 /* 16 bits */
9951 return 3;
9952 } else if (x < 0x200000UL) {
9953 /* 21 bits */
9954 return 4;
9955 } else if (x < 0x4000000UL) {
9956 /* 26 bits */
9957 return 5;
9958 } else if (x < (duk_ucodepoint_t) 0x80000000UL) {
9959 /* 31 bits */
9960 return 6;
9961 } else {
9962 /* 36 bits */
9963 return 7;
9964 }
9965}
9966
9967#if defined(DUK_USE_ASSERTIONS)
9968DUK_INTERNAL duk_small_int_t duk_unicode_get_cesu8_length(duk_ucodepoint_t cp) {
9969 duk_uint_fast32_t x = (duk_uint_fast32_t) cp;
9970 if (x < 0x80UL) {
9971 /* 7 bits */
9972 return 1;
9973 } else if (x < 0x800UL) {
9974 /* 11 bits */
9975 return 2;
9976 } else if (x < 0x10000UL) {
9977 /* 16 bits */
9978 return 3;
9979 } else {
9980 /* Encoded as surrogate pair, each encoding to 3 bytes for
9981 * 6 bytes total. Codepoints above U+10FFFF encode as 6 bytes
9982 * too, see duk_unicode_encode_cesu8().
9983 */
9984 return 3 + 3;
9985 }
9986}
9987#endif /* DUK_USE_ASSERTIONS */
9988
11fdf7f2 9989DUK_INTERNAL const duk_uint8_t duk_unicode_xutf8_markers[7] = {
7c673cae
FG
9990 0x00, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe
9991};
9992
9993/* Encode to extended UTF-8; 'out' must have space for at least
9994 * DUK_UNICODE_MAX_XUTF8_LENGTH bytes. Allows encoding of any
9995 * 32-bit (unsigned) codepoint.
9996 */
9997DUK_INTERNAL duk_small_int_t duk_unicode_encode_xutf8(duk_ucodepoint_t cp, duk_uint8_t *out) {
9998 duk_uint_fast32_t x = (duk_uint_fast32_t) cp;
9999 duk_small_int_t len;
10000 duk_uint8_t marker;
10001 duk_small_int_t i;
10002
10003 len = duk_unicode_get_xutf8_length(cp);
10004 DUK_ASSERT(len > 0);
10005
10006 marker = duk_unicode_xutf8_markers[len - 1]; /* 64-bit OK because always >= 0 */
10007
10008 i = len;
10009 DUK_ASSERT(i > 0);
10010 do {
10011 i--;
10012 if (i > 0) {
10013 out[i] = (duk_uint8_t) (0x80 + (x & 0x3f));
10014 x >>= 6;
10015 } else {
10016 /* Note: masking of 'x' is not necessary because of
10017 * range check and shifting -> no bits overlapping
10018 * the marker should be set.
10019 */
10020 out[0] = (duk_uint8_t) (marker + x);
10021 }
10022 } while (i > 0);
10023
10024 return len;
10025}
10026
10027/* Encode to CESU-8; 'out' must have space for at least
10028 * DUK_UNICODE_MAX_CESU8_LENGTH bytes; codepoints above U+10FFFF
10029 * will encode to garbage but won't overwrite the output buffer.
10030 */
10031DUK_INTERNAL duk_small_int_t duk_unicode_encode_cesu8(duk_ucodepoint_t cp, duk_uint8_t *out) {
10032 duk_uint_fast32_t x = (duk_uint_fast32_t) cp;
10033 duk_small_int_t len;
10034
10035 if (x < 0x80UL) {
10036 out[0] = (duk_uint8_t) x;
10037 len = 1;
10038 } else if (x < 0x800UL) {
10039 out[0] = (duk_uint8_t) (0xc0 + ((x >> 6) & 0x1f));
10040 out[1] = (duk_uint8_t) (0x80 + (x & 0x3f));
10041 len = 2;
10042 } else if (x < 0x10000UL) {
10043 /* surrogate pairs get encoded here */
10044 out[0] = (duk_uint8_t) (0xe0 + ((x >> 12) & 0x0f));
10045 out[1] = (duk_uint8_t) (0x80 + ((x >> 6) & 0x3f));
10046 out[2] = (duk_uint8_t) (0x80 + (x & 0x3f));
10047 len = 3;
10048 } else {
10049 /*
10050 * Unicode codepoints above U+FFFF are encoded as surrogate
10051 * pairs here. This ensures that all CESU-8 codepoints are
10052 * 16-bit values as expected in Ecmascript. The surrogate
10053 * pairs always get a 3-byte encoding (each) in CESU-8.
10054 * See: http://en.wikipedia.org/wiki/Surrogate_pair
10055 *
10056 * 20-bit codepoint, 10 bits (A and B) per surrogate pair:
10057 *
10058 * x = 0b00000000 0000AAAA AAAAAABB BBBBBBBB
10059 * sp1 = 0b110110AA AAAAAAAA (0xd800 + ((x >> 10) & 0x3ff))
10060 * sp2 = 0b110111BB BBBBBBBB (0xdc00 + (x & 0x3ff))
10061 *
10062 * Encoded into CESU-8:
10063 *
10064 * sp1 -> 0b11101101 (0xe0 + ((sp1 >> 12) & 0x0f))
10065 * -> 0b1010AAAA (0x80 + ((sp1 >> 6) & 0x3f))
10066 * -> 0b10AAAAAA (0x80 + (sp1 & 0x3f))
10067 * sp2 -> 0b11101101 (0xe0 + ((sp2 >> 12) & 0x0f))
10068 * -> 0b1011BBBB (0x80 + ((sp2 >> 6) & 0x3f))
10069 * -> 0b10BBBBBB (0x80 + (sp2 & 0x3f))
10070 *
10071 * Note that 0x10000 must be subtracted first. The code below
10072 * avoids the sp1, sp2 temporaries which saves around 20 bytes
10073 * of code.
10074 */
10075
10076 x -= 0x10000UL;
10077
10078 out[0] = (duk_uint8_t) (0xed);
10079 out[1] = (duk_uint8_t) (0xa0 + ((x >> 16) & 0x0f));
10080 out[2] = (duk_uint8_t) (0x80 + ((x >> 10) & 0x3f));
10081 out[3] = (duk_uint8_t) (0xed);
10082 out[4] = (duk_uint8_t) (0xb0 + ((x >> 6) & 0x0f));
10083 out[5] = (duk_uint8_t) (0x80 + (x & 0x3f));
10084 len = 6;
10085 }
10086
10087 return len;
10088}
10089
10090/* Decode helper. Return zero on error. */
10091DUK_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) {
10092 const duk_uint8_t *p;
10093 duk_uint32_t res;
10094 duk_uint_fast8_t ch;
10095 duk_small_int_t n;
10096
10097 DUK_UNREF(thr);
10098
10099 p = *ptr;
10100 if (p < ptr_start || p >= ptr_end) {
10101 goto fail;
10102 }
10103
10104 /*
10105 * UTF-8 decoder which accepts longer than standard byte sequences.
10106 * This allows full 32-bit code points to be used.
10107 */
10108
10109 ch = (duk_uint_fast8_t) (*p++);
10110 if (ch < 0x80) {
10111 /* 0xxx xxxx [7 bits] */
10112 res = (duk_uint32_t) (ch & 0x7f);
10113 n = 0;
10114 } else if (ch < 0xc0) {
10115 /* 10xx xxxx -> invalid */
10116 goto fail;
10117 } else if (ch < 0xe0) {
10118 /* 110x xxxx 10xx xxxx [11 bits] */
10119 res = (duk_uint32_t) (ch & 0x1f);
10120 n = 1;
10121 } else if (ch < 0xf0) {
10122 /* 1110 xxxx 10xx xxxx 10xx xxxx [16 bits] */
10123 res = (duk_uint32_t) (ch & 0x0f);
10124 n = 2;
10125 } else if (ch < 0xf8) {
10126 /* 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx [21 bits] */
10127 res = (duk_uint32_t) (ch & 0x07);
10128 n = 3;
10129 } else if (ch < 0xfc) {
10130 /* 1111 10xx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [26 bits] */
10131 res = (duk_uint32_t) (ch & 0x03);
10132 n = 4;
10133 } else if (ch < 0xfe) {
10134 /* 1111 110x 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [31 bits] */
10135 res = (duk_uint32_t) (ch & 0x01);
10136 n = 5;
10137 } else if (ch < 0xff) {
10138 /* 1111 1110 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [36 bits] */
10139 res = (duk_uint32_t) (0);
10140 n = 6;
10141 } else {
10142 /* 8-byte format could be:
10143 * 1111 1111 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [41 bits]
10144 *
10145 * However, this format would not have a zero bit following the
10146 * leading one bits and would not allow 0xFF to be used as an
10147 * "invalid xutf-8" marker for internal keys. Further, 8-byte
10148 * encodings (up to 41 bit code points) are not currently needed.
10149 */
10150 goto fail;
10151 }
10152
10153 DUK_ASSERT(p >= ptr_start); /* verified at beginning */
10154 if (p + n > ptr_end) {
10155 /* check pointer at end */
10156 goto fail;
10157 }
10158
10159 while (n > 0) {
10160 DUK_ASSERT(p >= ptr_start && p < ptr_end);
10161 res = res << 6;
10162 res += (duk_uint32_t) ((*p++) & 0x3f);
10163 n--;
10164 }
10165
10166 *ptr = p;
10167 *out_cp = res;
10168 return 1;
10169
10170 fail:
10171 return 0;
10172}
10173
10174/* used by e.g. duk_regexp_executor.c, string built-ins */
10175DUK_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) {
10176 duk_ucodepoint_t cp;
10177
10178 if (duk_unicode_decode_xutf8(thr, ptr, ptr_start, ptr_end, &cp)) {
10179 return cp;
10180 }
11fdf7f2 10181 DUK_ERROR_INTERNAL(thr, "utf-8 decode failed"); /* XXX: 'internal error' is a bit of a misnomer */
7c673cae
FG
10182 DUK_UNREACHABLE();
10183 return 0;
10184}
10185
11fdf7f2
TL
10186/* Compute (extended) utf-8 length without codepoint encoding validation,
10187 * used for string interning.
10188 *
10189 * NOTE: This algorithm is performance critical, more so than string hashing
10190 * in some cases. It is needed when interning a string and needs to scan
10191 * every byte of the string with no skipping. Having an ASCII fast path
10192 * is useful if possible in the algorithm. The current algorithms were
10193 * chosen from several variants, based on x64 gcc -O2 testing. See:
10194 * https://github.com/svaarala/duktape/pull/422
10195 *
10196 * NOTE: must match src/dukutil.py:duk_unicode_unvalidated_utf8_length().
7c673cae 10197 */
11fdf7f2
TL
10198
10199#if defined(DUK_USE_PREFER_SIZE)
10200/* Small variant; roughly 150 bytes smaller than the fast variant. */
7c673cae 10201DUK_INTERNAL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen) {
11fdf7f2
TL
10202 const duk_uint8_t *p;
10203 const duk_uint8_t *p_end;
10204 duk_size_t ncont;
10205 duk_size_t clen;
7c673cae 10206
11fdf7f2
TL
10207 p = data;
10208 p_end = data + blen;
10209 ncont = 0;
10210 while (p != p_end) {
10211 duk_uint8_t x;
10212 x = *p++;
10213 if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) {
10214 ncont++;
10215 }
10216 }
10217
10218 DUK_ASSERT(ncont <= blen);
10219 clen = blen - ncont;
10220 DUK_ASSERT(clen <= blen);
10221 return clen;
10222}
10223#else /* DUK_USE_PREFER_SIZE */
10224/* This seems like a good overall approach. Fast path for ASCII in 4 byte
10225 * blocks.
10226 */
10227DUK_INTERNAL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen) {
10228 const duk_uint8_t *p;
10229 const duk_uint8_t *p_end;
10230 const duk_uint32_t *p32_end;
10231 const duk_uint32_t *p32;
10232 duk_size_t ncont;
10233 duk_size_t clen;
10234
10235 ncont = 0; /* number of continuation (non-initial) bytes in [0x80,0xbf] */
10236 p = data;
10237 p_end = data + blen;
10238 if (blen < 16) {
10239 goto skip_fastpath;
10240 }
10241
10242 /* Align 'p' to 4; the input data may have arbitrary alignment.
10243 * End of string check not needed because blen >= 16.
10244 */
10245 while (((duk_size_t) (const void *) p) & 0x03U) {
10246 duk_uint8_t x;
10247 x = *p++;
10248 if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) {
10249 ncont++;
10250 }
10251 }
10252
10253 /* Full, aligned 4-byte reads. */
10254 p32_end = (const duk_uint32_t *) (const void *) (p + ((duk_size_t) (p_end - p) & (duk_size_t) (~0x03)));
10255 p32 = (const duk_uint32_t *) (const void *) p;
10256 while (p32 != (const duk_uint32_t *) p32_end) {
10257 duk_uint32_t x;
10258 x = *p32++;
10259 if (DUK_LIKELY((x & 0x80808080UL) == 0)) {
10260 ; /* ASCII fast path */
10261 } else {
10262 /* Flip highest bit of each byte which changes
10263 * the bit pattern 10xxxxxx into 00xxxxxx which
10264 * allows an easy bit mask test.
7c673cae 10265 */
11fdf7f2
TL
10266 x ^= 0x80808080UL;
10267 if (DUK_UNLIKELY(!(x & 0xc0000000UL))) {
10268 ncont++;
10269 }
10270 if (DUK_UNLIKELY(!(x & 0x00c00000UL))) {
10271 ncont++;
10272 }
10273 if (DUK_UNLIKELY(!(x & 0x0000c000UL))) {
10274 ncont++;
10275 }
10276 if (DUK_UNLIKELY(!(x & 0x000000c0UL))) {
10277 ncont++;
10278 }
7c673cae
FG
10279 }
10280 }
11fdf7f2
TL
10281 p = (const duk_uint8_t *) p32;
10282 /* Fall through to handle the rest. */
7c673cae 10283
11fdf7f2
TL
10284 skip_fastpath:
10285 while (p != p_end) {
10286 duk_uint8_t x;
10287 x = *p++;
10288 if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) {
10289 ncont++;
10290 }
10291 }
10292
10293 DUK_ASSERT(ncont <= blen);
10294 clen = blen - ncont;
10295 DUK_ASSERT(clen <= blen);
7c673cae
FG
10296 return clen;
10297}
11fdf7f2 10298#endif /* DUK_USE_PREFER_SIZE */
7c673cae
FG
10299
10300/*
10301 * Unicode range matcher
10302 *
10303 * Matches a codepoint against a packed bitstream of character ranges.
10304 * Used for slow path Unicode matching.
10305 */
10306
10307/* Must match src/extract_chars.py, generate_match_table3(). */
10308DUK_LOCAL duk_uint32_t duk__uni_decode_value(duk_bitdecoder_ctx *bd_ctx) {
10309 duk_uint32_t t;
10310
10311 t = (duk_uint32_t) duk_bd_decode(bd_ctx, 4);
10312 if (t <= 0x0eU) {
10313 return t;
10314 }
10315 t = (duk_uint32_t) duk_bd_decode(bd_ctx, 8);
10316 if (t <= 0xfdU) {
10317 return t + 0x0f;
10318 }
10319 if (t == 0xfeU) {
10320 t = (duk_uint32_t) duk_bd_decode(bd_ctx, 12);
10321 return t + 0x0fU + 0xfeU;
10322 } else {
10323 t = (duk_uint32_t) duk_bd_decode(bd_ctx, 24);
10324 return t + 0x0fU + 0xfeU + 0x1000UL;
10325 }
10326}
10327
10328DUK_LOCAL duk_small_int_t duk__uni_range_match(const duk_uint8_t *unitab, duk_size_t unilen, duk_codepoint_t cp) {
10329 duk_bitdecoder_ctx bd_ctx;
10330 duk_codepoint_t prev_re;
10331
10332 DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
11fdf7f2 10333 bd_ctx.data = (const duk_uint8_t *) unitab;
7c673cae
FG
10334 bd_ctx.length = (duk_size_t) unilen;
10335
10336 prev_re = 0;
10337 for (;;) {
10338 duk_codepoint_t r1, r2;
10339 r1 = (duk_codepoint_t) duk__uni_decode_value(&bd_ctx);
10340 if (r1 == 0) {
10341 break;
10342 }
10343 r2 = (duk_codepoint_t) duk__uni_decode_value(&bd_ctx);
10344
10345 r1 = prev_re + r1;
10346 r2 = r1 + r2;
10347 prev_re = r2;
10348
10349 /* [r1,r2] is the range */
10350
10351 DUK_DDD(DUK_DDDPRINT("duk__uni_range_match: cp=%06lx range=[0x%06lx,0x%06lx]",
10352 (unsigned long) cp, (unsigned long) r1, (unsigned long) r2));
10353 if (cp >= r1 && cp <= r2) {
10354 return 1;
10355 }
10356 }
10357
10358 return 0;
10359}
10360
10361/*
10362 * "WhiteSpace" production check.
10363 */
10364
10365DUK_INTERNAL duk_small_int_t duk_unicode_is_whitespace(duk_codepoint_t cp) {
10366 /*
10367 * E5 Section 7.2 specifies six characters specifically as
10368 * white space:
10369 *
10370 * 0009;<control>;Cc;0;S;;;;;N;CHARACTER TABULATION;;;;
10371 * 000B;<control>;Cc;0;S;;;;;N;LINE TABULATION;;;;
10372 * 000C;<control>;Cc;0;WS;;;;;N;FORM FEED (FF);;;;
10373 * 0020;SPACE;Zs;0;WS;;;;;N;;;;;
10374 * 00A0;NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;NON-BREAKING SPACE;;;;
10375 * FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;;
10376 *
10377 * It also specifies any Unicode category 'Zs' characters as white
10378 * space. These can be extracted with the "src/extract_chars.py" script.
10379 * Current result:
10380 *
10381 * RAW OUTPUT:
10382 * ===========
10383 * 0020;SPACE;Zs;0;WS;;;;;N;;;;;
10384 * 00A0;NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;NON-BREAKING SPACE;;;;
10385 * 1680;OGHAM SPACE MARK;Zs;0;WS;;;;;N;;;;;
10386 * 180E;MONGOLIAN VOWEL SEPARATOR;Zs;0;WS;;;;;N;;;;;
10387 * 2000;EN QUAD;Zs;0;WS;2002;;;;N;;;;;
10388 * 2001;EM QUAD;Zs;0;WS;2003;;;;N;;;;;
10389 * 2002;EN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
10390 * 2003;EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
10391 * 2004;THREE-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
10392 * 2005;FOUR-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
10393 * 2006;SIX-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
10394 * 2007;FIGURE SPACE;Zs;0;WS;<noBreak> 0020;;;;N;;;;;
10395 * 2008;PUNCTUATION SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
10396 * 2009;THIN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
10397 * 200A;HAIR SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
10398 * 202F;NARROW NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;;;;;
10399 * 205F;MEDIUM MATHEMATICAL SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
10400 * 3000;IDEOGRAPHIC SPACE;Zs;0;WS;<wide> 0020;;;;N;;;;;
10401 *
10402 * RANGES:
10403 * =======
10404 * 0x0020
10405 * 0x00a0
10406 * 0x1680
10407 * 0x180e
10408 * 0x2000 ... 0x200a
10409 * 0x202f
10410 * 0x205f
10411 * 0x3000
10412 *
10413 * A manual decoder (below) is probably most compact for this.
10414 */
10415
10416 duk_uint_fast8_t lo;
10417 duk_uint_fast32_t hi;
10418
10419 /* cp == -1 (EOF) never matches and causes return value 0 */
10420
10421 lo = (duk_uint_fast8_t) (cp & 0xff);
10422 hi = (duk_uint_fast32_t) (cp >> 8); /* does not fit into an uchar */
10423
10424 if (hi == 0x0000UL) {
10425 if (lo == 0x09U || lo == 0x0bU || lo == 0x0cU ||
10426 lo == 0x20U || lo == 0xa0U) {
10427 return 1;
10428 }
10429 } else if (hi == 0x0020UL) {
10430 if (lo <= 0x0aU || lo == 0x2fU || lo == 0x5fU) {
10431 return 1;
10432 }
10433 } else if (cp == 0x1680L || cp == 0x180eL || cp == 0x3000L ||
10434 cp == 0xfeffL) {
10435 return 1;
10436 }
10437
10438 return 0;
10439}
10440
10441/*
10442 * "LineTerminator" production check.
10443 */
10444
10445DUK_INTERNAL duk_small_int_t duk_unicode_is_line_terminator(duk_codepoint_t cp) {
10446 /*
10447 * E5 Section 7.3
10448 *
10449 * A LineTerminatorSequence essentially merges <CR> <LF> sequences
10450 * into a single line terminator. This must be handled by the caller.
10451 */
10452
10453 if (cp == 0x000aL || cp == 0x000dL || cp == 0x2028L ||
10454 cp == 0x2029L) {
10455 return 1;
10456 }
10457
10458 return 0;
10459}
10460
10461/*
10462 * "IdentifierStart" production check.
10463 */
10464
10465DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_t cp) {
10466 /*
10467 * E5 Section 7.6:
10468 *
10469 * IdentifierStart:
10470 * UnicodeLetter
10471 * $
10472 * _
10473 * \ UnicodeEscapeSequence
10474 *
10475 * IdentifierStart production has one multi-character production:
10476 *
10477 * \ UnicodeEscapeSequence
10478 *
10479 * The '\' character is -not- matched by this function. Rather, the caller
10480 * should decode the escape and then call this function to check whether the
10481 * decoded character is acceptable (see discussion in E5 Section 7.6).
10482 *
10483 * The "UnicodeLetter" alternative of the production allows letters
10484 * from various Unicode categories. These can be extracted with the
10485 * "src/extract_chars.py" script.
10486 *
10487 * Because the result has hundreds of Unicode codepoint ranges, matching
10488 * for any values >= 0x80 are done using a very slow range-by-range scan
10489 * and a packed range format.
10490 *
10491 * The ASCII portion (codepoints 0x00 ... 0x7f) is fast-pathed below because
10492 * it matters the most. The ASCII related ranges of IdentifierStart are:
10493 *
10494 * 0x0041 ... 0x005a ['A' ... 'Z']
10495 * 0x0061 ... 0x007a ['a' ... 'z']
10496 * 0x0024 ['$']
10497 * 0x005f ['_']
10498 */
10499
10500 /* ASCII (and EOF) fast path -- quick accept and reject */
10501 if (cp <= 0x7fL) {
11fdf7f2
TL
10502#if defined(DUK_USE_IDCHAR_FASTPATH)
10503 return (cp >= 0) && (duk_is_idchar_tab[cp] > 0);
10504#else
7c673cae
FG
10505 if ((cp >= 'a' && cp <= 'z') ||
10506 (cp >= 'A' && cp <= 'Z') ||
10507 cp == '_' || cp == '$') {
10508 return 1;
10509 }
10510 return 0;
11fdf7f2 10511#endif
7c673cae
FG
10512 }
10513
10514 /* Non-ASCII slow path (range-by-range linear comparison), very slow */
10515
10516#ifdef DUK_USE_SOURCE_NONBMP
10517 if (duk__uni_range_match(duk_unicode_ids_noa,
10518 (duk_size_t) sizeof(duk_unicode_ids_noa),
10519 (duk_codepoint_t) cp)) {
10520 return 1;
10521 }
10522 return 0;
10523#else
10524 if (cp < 0x10000L) {
10525 if (duk__uni_range_match(duk_unicode_ids_noabmp,
10526 sizeof(duk_unicode_ids_noabmp),
10527 (duk_codepoint_t) cp)) {
10528 return 1;
10529 }
10530 return 0;
10531 } else {
10532 /* without explicit non-BMP support, assume non-BMP characters
10533 * are always accepted as identifier characters.
10534 */
10535 return 1;
10536 }
10537#endif
10538}
10539
10540/*
10541 * "IdentifierPart" production check.
10542 */
10543
10544DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp) {
10545 /*
10546 * E5 Section 7.6:
10547 *
10548 * IdentifierPart:
10549 * IdentifierStart
10550 * UnicodeCombiningMark
10551 * UnicodeDigit
10552 * UnicodeConnectorPunctuation
10553 * <ZWNJ> [U+200C]
10554 * <ZWJ> [U+200D]
10555 *
10556 * IdentifierPart production has one multi-character production
10557 * as part of its IdentifierStart alternative. The '\' character
10558 * of an escape sequence is not matched here, see discussion in
10559 * duk_unicode_is_identifier_start().
10560 *
10561 * To match non-ASCII characters (codepoints >= 0x80), a very slow
10562 * linear range-by-range scan is used. The codepoint is first compared
10563 * to the IdentifierStart ranges, and if it doesn't match, then to a
10564 * set consisting of code points in IdentifierPart but not in
10565 * IdentifierStart. This is done to keep the unicode range data small,
10566 * at the expense of speed.
10567 *
10568 * The ASCII fast path consists of:
10569 *
10570 * 0x0030 ... 0x0039 ['0' ... '9', UnicodeDigit]
10571 * 0x0041 ... 0x005a ['A' ... 'Z', IdentifierStart]
10572 * 0x0061 ... 0x007a ['a' ... 'z', IdentifierStart]
10573 * 0x0024 ['$', IdentifierStart]
10574 * 0x005f ['_', IdentifierStart and
10575 * UnicodeConnectorPunctuation]
10576 *
10577 * UnicodeCombiningMark has no code points <= 0x7f.
10578 *
10579 * The matching code reuses the "identifier start" tables, and then
10580 * consults a separate range set for characters in "identifier part"
10581 * but not in "identifier start". These can be extracted with the
10582 * "src/extract_chars.py" script.
10583 *
10584 * UnicodeCombiningMark -> categories Mn, Mc
10585 * UnicodeDigit -> categories Nd
10586 * UnicodeConnectorPunctuation -> categories Pc
10587 */
10588
10589 /* ASCII (and EOF) fast path -- quick accept and reject */
10590 if (cp <= 0x7fL) {
11fdf7f2
TL
10591#if defined(DUK_USE_IDCHAR_FASTPATH)
10592 return (cp >= 0) && (duk_is_idchar_tab[cp] != 0);
10593#else
7c673cae
FG
10594 if ((cp >= 'a' && cp <= 'z') ||
10595 (cp >= 'A' && cp <= 'Z') ||
10596 (cp >= '0' && cp <= '9') ||
10597 cp == '_' || cp == '$') {
10598 return 1;
10599 }
10600 return 0;
11fdf7f2 10601#endif
7c673cae
FG
10602 }
10603
10604 /* Non-ASCII slow path (range-by-range linear comparison), very slow */
10605
10606#ifdef DUK_USE_SOURCE_NONBMP
10607 if (duk__uni_range_match(duk_unicode_ids_noa,
10608 sizeof(duk_unicode_ids_noa),
10609 (duk_codepoint_t) cp) ||
10610 duk__uni_range_match(duk_unicode_idp_m_ids_noa,
10611 sizeof(duk_unicode_idp_m_ids_noa),
10612 (duk_codepoint_t) cp)) {
10613 return 1;
10614 }
10615 return 0;
10616#else
10617 if (cp < 0x10000L) {
10618 if (duk__uni_range_match(duk_unicode_ids_noabmp,
10619 sizeof(duk_unicode_ids_noabmp),
10620 (duk_codepoint_t) cp) ||
10621 duk__uni_range_match(duk_unicode_idp_m_ids_noabmp,
10622 sizeof(duk_unicode_idp_m_ids_noabmp),
10623 (duk_codepoint_t) cp)) {
10624 return 1;
10625 }
10626 return 0;
10627 } else {
10628 /* without explicit non-BMP support, assume non-BMP characters
10629 * are always accepted as identifier characters.
10630 */
10631 return 1;
10632 }
10633#endif
10634}
10635
10636/*
10637 * Unicode letter check.
10638 */
10639
10640DUK_INTERNAL duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp) {
10641 /*
10642 * Unicode letter is now taken to be the categories:
10643 *
10644 * Lu, Ll, Lt, Lm, Lo
10645 *
10646 * (Not sure if this is exactly correct.)
10647 *
10648 * The ASCII fast path consists of:
10649 *
10650 * 0x0041 ... 0x005a ['A' ... 'Z']
10651 * 0x0061 ... 0x007a ['a' ... 'z']
10652 */
10653
10654 /* ASCII (and EOF) fast path -- quick accept and reject */
10655 if (cp <= 0x7fL) {
10656 if ((cp >= 'a' && cp <= 'z') ||
10657 (cp >= 'A' && cp <= 'Z')) {
10658 return 1;
10659 }
10660 return 0;
10661 }
10662
10663 /* Non-ASCII slow path (range-by-range linear comparison), very slow */
10664
10665#ifdef DUK_USE_SOURCE_NONBMP
10666 if (duk__uni_range_match(duk_unicode_ids_noa,
10667 sizeof(duk_unicode_ids_noa),
10668 (duk_codepoint_t) cp) &&
10669 !duk__uni_range_match(duk_unicode_ids_m_let_noa,
10670 sizeof(duk_unicode_ids_m_let_noa),
10671 (duk_codepoint_t) cp)) {
10672 return 1;
10673 }
10674 return 0;
10675#else
10676 if (cp < 0x10000L) {
10677 if (duk__uni_range_match(duk_unicode_ids_noabmp,
10678 sizeof(duk_unicode_ids_noabmp),
10679 (duk_codepoint_t) cp) &&
10680 !duk__uni_range_match(duk_unicode_ids_m_let_noabmp,
10681 sizeof(duk_unicode_ids_m_let_noabmp),
10682 (duk_codepoint_t) cp)) {
10683 return 1;
10684 }
10685 return 0;
10686 } else {
10687 /* without explicit non-BMP support, assume non-BMP characters
10688 * are always accepted as letters.
10689 */
10690 return 1;
10691 }
10692#endif
10693}
10694
10695/*
10696 * Complex case conversion helper which decodes a bit-packed conversion
10697 * control stream generated by unicode/extract_caseconv.py. The conversion
10698 * is very slow because it runs through the conversion data in a linear
10699 * fashion to save space (which is why ASCII characters have a special
10700 * fast path before arriving here).
10701 *
10702 * The particular bit counts etc have been determined experimentally to
10703 * be small but still sufficient, and must match the Python script
10704 * (src/extract_caseconv.py).
10705 *
10706 * The return value is the case converted codepoint or -1 if the conversion
10707 * results in multiple characters (this is useful for regexp Canonicalization
10708 * operation). If 'buf' is not NULL, the result codepoint(s) are also
10709 * appended to the hbuffer.
10710 *
10711 * Context and locale specific rules must be checked before consulting
10712 * this function.
10713 */
10714
10715DUK_LOCAL
10716duk_codepoint_t duk__slow_case_conversion(duk_hthread *thr,
10717 duk_bufwriter_ctx *bw,
10718 duk_codepoint_t cp,
10719 duk_bitdecoder_ctx *bd_ctx) {
10720 duk_small_int_t skip = 0;
10721 duk_small_int_t n;
10722 duk_small_int_t t;
10723 duk_small_int_t count;
10724 duk_codepoint_t tmp_cp;
10725 duk_codepoint_t start_i;
10726 duk_codepoint_t start_o;
10727
10728 DUK_UNREF(thr);
10729 DUK_ASSERT(bd_ctx != NULL);
10730
10731 DUK_DDD(DUK_DDDPRINT("slow case conversion for codepoint: %ld", (long) cp));
10732
10733 /* range conversion with a "skip" */
10734 DUK_DDD(DUK_DDDPRINT("checking ranges"));
10735 for (;;) {
10736 skip++;
10737 n = (duk_small_int_t) duk_bd_decode(bd_ctx, 6);
10738 if (n == 0x3f) {
10739 /* end marker */
10740 break;
10741 }
10742 DUK_DDD(DUK_DDDPRINT("skip=%ld, n=%ld", (long) skip, (long) n));
10743
10744 while (n--) {
10745 start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
10746 start_o = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
10747 count = (duk_small_int_t) duk_bd_decode(bd_ctx, 7);
10748 DUK_DDD(DUK_DDDPRINT("range: start_i=%ld, start_o=%ld, count=%ld, skip=%ld",
10749 (long) start_i, (long) start_o, (long) count, (long) skip));
10750
10751 if (cp >= start_i) {
10752 tmp_cp = cp - start_i; /* always >= 0 */
10753 if (tmp_cp < (duk_codepoint_t) count * (duk_codepoint_t) skip &&
10754 (tmp_cp % (duk_codepoint_t) skip) == 0) {
10755 DUK_DDD(DUK_DDDPRINT("range matches input codepoint"));
10756 cp = start_o + tmp_cp;
10757 goto single;
10758 }
10759 }
10760 }
10761 }
10762
10763 /* 1:1 conversion */
10764 n = (duk_small_int_t) duk_bd_decode(bd_ctx, 6);
10765 DUK_DDD(DUK_DDDPRINT("checking 1:1 conversions (count %ld)", (long) n));
10766 while (n--) {
10767 start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
10768 start_o = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
10769 DUK_DDD(DUK_DDDPRINT("1:1 conversion %ld -> %ld", (long) start_i, (long) start_o));
10770 if (cp == start_i) {
10771 DUK_DDD(DUK_DDDPRINT("1:1 matches input codepoint"));
10772 cp = start_o;
10773 goto single;
10774 }
10775 }
10776
10777 /* complex, multicharacter conversion */
10778 n = (duk_small_int_t) duk_bd_decode(bd_ctx, 7);
10779 DUK_DDD(DUK_DDDPRINT("checking 1:n conversions (count %ld)", (long) n));
10780 while (n--) {
10781 start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
10782 t = (duk_small_int_t) duk_bd_decode(bd_ctx, 2);
10783 DUK_DDD(DUK_DDDPRINT("1:n conversion %ld -> %ld chars", (long) start_i, (long) t));
10784 if (cp == start_i) {
10785 DUK_DDD(DUK_DDDPRINT("1:n matches input codepoint"));
10786 if (bw != NULL) {
10787 while (t--) {
10788 tmp_cp = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
10789 DUK_BW_WRITE_RAW_XUTF8(thr, bw, (duk_ucodepoint_t) tmp_cp);
10790 }
10791 }
10792 return -1;
10793 } else {
10794 while (t--) {
10795 (void) duk_bd_decode(bd_ctx, 16);
10796 }
10797 }
10798 }
10799
10800 /* default: no change */
10801 DUK_DDD(DUK_DDDPRINT("no rule matches, output is same as input"));
10802 /* fall through */
10803
10804 single:
10805 if (bw != NULL) {
10806 DUK_BW_WRITE_RAW_XUTF8(thr, bw, (duk_ucodepoint_t) cp);
10807 }
10808 return cp;
10809}
10810
10811/*
10812 * Case conversion helper, with context/local sensitivity.
10813 * For proper case conversion, one needs to know the character
10814 * and the preceding and following characters, as well as
10815 * locale/language.
10816 */
10817
10818/* XXX: add 'language' argument when locale/language sensitive rule
10819 * support added.
10820 */
10821DUK_LOCAL
10822duk_codepoint_t duk__case_transform_helper(duk_hthread *thr,
10823 duk_bufwriter_ctx *bw,
10824 duk_codepoint_t cp,
10825 duk_codepoint_t prev,
10826 duk_codepoint_t next,
10827 duk_bool_t uppercase) {
10828 duk_bitdecoder_ctx bd_ctx;
10829
10830 /* fast path for ASCII */
10831 if (cp < 0x80L) {
10832 /* XXX: there are language sensitive rules for the ASCII range.
10833 * If/when language/locale support is implemented, they need to
10834 * be implemented here for the fast path. There are no context
10835 * sensitive rules for ASCII range.
10836 */
10837
10838 if (uppercase) {
10839 if (cp >= 'a' && cp <= 'z') {
10840 cp = cp - 'a' + 'A';
10841 }
10842 } else {
10843 if (cp >= 'A' && cp <= 'Z') {
10844 cp = cp - 'A' + 'a';
10845 }
10846 }
10847
10848 if (bw != NULL) {
10849 DUK_BW_WRITE_RAW_U8(thr, bw, (duk_uint8_t) cp);
10850 }
10851 return cp;
10852 }
10853
10854 /* context and locale specific rules which cannot currently be represented
10855 * in the caseconv bitstream: hardcoded rules in C
10856 */
10857 if (uppercase) {
10858 /* XXX: turkish / azeri */
10859 } else {
10860 /*
10861 * Final sigma context specific rule. This is a rather tricky
10862 * rule and this handling is probably not 100% correct now.
10863 * The rule is not locale/language specific so it is supported.
10864 */
10865
10866 if (cp == 0x03a3L && /* U+03A3 = GREEK CAPITAL LETTER SIGMA */
10867 duk_unicode_is_letter(prev) && /* prev exists and is not a letter */
10868 !duk_unicode_is_letter(next)) { /* next does not exist or next is not a letter */
10869 /* Capital sigma occurred at "end of word", lowercase to
10870 * U+03C2 = GREEK SMALL LETTER FINAL SIGMA. Otherwise
10871 * fall through and let the normal rules lowercase it to
10872 * U+03C3 = GREEK SMALL LETTER SIGMA.
10873 */
10874 cp = 0x03c2L;
10875 goto singlechar;
10876 }
10877
10878 /* XXX: lithuanian not implemented */
10879 /* XXX: lithuanian, explicit dot rules */
10880 /* XXX: turkish / azeri, lowercase rules */
10881 }
10882
10883 /* 1:1 or special conversions, but not locale/context specific: script generated rules */
10884 DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
10885 if (uppercase) {
11fdf7f2 10886 bd_ctx.data = (const duk_uint8_t *) duk_unicode_caseconv_uc;
7c673cae
FG
10887 bd_ctx.length = (duk_size_t) sizeof(duk_unicode_caseconv_uc);
10888 } else {
11fdf7f2 10889 bd_ctx.data = (const duk_uint8_t *) duk_unicode_caseconv_lc;
7c673cae
FG
10890 bd_ctx.length = (duk_size_t) sizeof(duk_unicode_caseconv_lc);
10891 }
10892 return duk__slow_case_conversion(thr, bw, cp, &bd_ctx);
10893
10894 singlechar:
10895 if (bw != NULL) {
10896 DUK_BW_WRITE_RAW_XUTF8(thr, bw, (duk_ucodepoint_t) cp);
10897 }
10898 return cp;
10899
10900 /* unused now, not needed until Turkish/Azeri */
10901#if 0
10902 nochar:
10903 return -1;
10904#endif
10905}
10906
10907/*
10908 * Replace valstack top with case converted version.
10909 */
10910
10911DUK_INTERNAL void duk_unicode_case_convert_string(duk_hthread *thr, duk_small_int_t uppercase) {
10912 duk_context *ctx = (duk_context *) thr;
10913 duk_hstring *h_input;
10914 duk_bufwriter_ctx bw_alloc;
10915 duk_bufwriter_ctx *bw;
10916 const duk_uint8_t *p, *p_start, *p_end;
10917 duk_codepoint_t prev, curr, next;
10918
10919 h_input = duk_require_hstring(ctx, -1);
10920 DUK_ASSERT(h_input != NULL);
10921
10922 bw = &bw_alloc;
10923 DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input));
10924
10925 /* [ ... input buffer ] */
10926
11fdf7f2 10927 p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
7c673cae
FG
10928 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
10929 p = p_start;
10930
10931 prev = -1; DUK_UNREF(prev);
10932 curr = -1;
10933 next = -1;
10934 for (;;) {
10935 prev = curr;
10936 curr = next;
10937 next = -1;
10938 if (p < p_end) {
10939 next = (int) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
10940 } else {
10941 /* end of input and last char has been processed */
10942 if (curr < 0) {
10943 break;
10944 }
10945 }
10946
10947 /* on first round, skip */
10948 if (curr >= 0) {
10949 /* XXX: could add a fast path to process chunks of input codepoints,
10950 * but relative benefit would be quite small.
10951 */
10952
10953 /* Ensure space for maximum multi-character result; estimate is overkill. */
10954 DUK_BW_ENSURE(thr, bw, 8 * DUK_UNICODE_MAX_XUTF8_LENGTH);
10955
10956 duk__case_transform_helper(thr,
10957 bw,
10958 (duk_codepoint_t) curr,
10959 prev,
10960 next,
10961 uppercase);
10962 }
10963 }
10964
10965 DUK_BW_COMPACT(thr, bw);
10966 duk_to_string(ctx, -1); /* invalidates h_buf pointer */
10967 duk_remove(ctx, -2);
10968}
10969
10970#ifdef DUK_USE_REGEXP_SUPPORT
10971
10972/*
10973 * Canonicalize() abstract operation needed for canonicalization of individual
10974 * codepoints during regexp compilation and execution, see E5 Section 15.10.2.8.
10975 * Note that codepoints are canonicalized one character at a time, so no context
10976 * specific rules can apply. Locale specific rules can apply, though.
10977 */
10978
10979DUK_INTERNAL duk_codepoint_t duk_unicode_re_canonicalize_char(duk_hthread *thr, duk_codepoint_t cp) {
11fdf7f2
TL
10980#if defined(DUK_USE_REGEXP_CANON_WORKAROUND)
10981 /* Fast canonicalization lookup at the cost of 128kB footprint. */
10982 DUK_ASSERT(cp >= 0);
10983 DUK_UNREF(thr);
10984 if (DUK_LIKELY(cp < 0x10000L)) {
10985 return (duk_codepoint_t) duk_unicode_re_canon_lookup[cp];
10986 }
10987 return cp;
10988#else /* DUK_USE_REGEXP_CANON_WORKAROUND */
7c673cae
FG
10989 duk_codepoint_t y;
10990
10991 y = duk__case_transform_helper(thr,
10992 NULL, /* NULL is allowed, no output */
10993 cp, /* curr char */
10994 -1, /* prev char */
10995 -1, /* next char */
10996 1); /* uppercase */
10997
10998 if ((y < 0) || (cp >= 0x80 && y < 0x80)) {
10999 /* multiple codepoint conversion or non-ASCII mapped to ASCII
11000 * --> leave as is.
11001 */
11002 return cp;
11003 }
11004
11005 return y;
11fdf7f2 11006#endif /* DUK_USE_REGEXP_CANON_WORKAROUND */
7c673cae
FG
11007}
11008
11009/*
11010 * E5 Section 15.10.2.6 "IsWordChar" abstract operation. Assume
11011 * x < 0 for characters read outside the string.
11012 */
11013
11014DUK_INTERNAL duk_small_int_t duk_unicode_re_is_wordchar(duk_codepoint_t x) {
11015 /*
11016 * Note: the description in E5 Section 15.10.2.6 has a typo, it
11017 * contains 'A' twice and lacks 'a'; the intent is [0-9a-zA-Z_].
11018 */
11019 if ((x >= '0' && x <= '9') ||
11020 (x >= 'a' && x <= 'z') ||
11021 (x >= 'A' && x <= 'Z') ||
11022 (x == '_')) {
11023 return 1;
11024 }
11025 return 0;
11026}
11027
11028/*
11029 * Regexp range tables
11030 */
11031
11032/* exposed because lexer needs these too */
11fdf7f2 11033DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_digit[2] = {
7c673cae
FG
11034 (duk_uint16_t) 0x0030UL, (duk_uint16_t) 0x0039UL,
11035};
11fdf7f2 11036DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_white[22] = {
7c673cae
FG
11037 (duk_uint16_t) 0x0009UL, (duk_uint16_t) 0x000DUL,
11038 (duk_uint16_t) 0x0020UL, (duk_uint16_t) 0x0020UL,
11039 (duk_uint16_t) 0x00A0UL, (duk_uint16_t) 0x00A0UL,
11040 (duk_uint16_t) 0x1680UL, (duk_uint16_t) 0x1680UL,
11041 (duk_uint16_t) 0x180EUL, (duk_uint16_t) 0x180EUL,
11042 (duk_uint16_t) 0x2000UL, (duk_uint16_t) 0x200AUL,
11043 (duk_uint16_t) 0x2028UL, (duk_uint16_t) 0x2029UL,
11044 (duk_uint16_t) 0x202FUL, (duk_uint16_t) 0x202FUL,
11045 (duk_uint16_t) 0x205FUL, (duk_uint16_t) 0x205FUL,
11046 (duk_uint16_t) 0x3000UL, (duk_uint16_t) 0x3000UL,
11047 (duk_uint16_t) 0xFEFFUL, (duk_uint16_t) 0xFEFFUL,
11048};
11fdf7f2 11049DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_wordchar[8] = {
7c673cae
FG
11050 (duk_uint16_t) 0x0030UL, (duk_uint16_t) 0x0039UL,
11051 (duk_uint16_t) 0x0041UL, (duk_uint16_t) 0x005AUL,
11052 (duk_uint16_t) 0x005FUL, (duk_uint16_t) 0x005FUL,
11053 (duk_uint16_t) 0x0061UL, (duk_uint16_t) 0x007AUL,
11054};
11fdf7f2 11055DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_digit[4] = {
7c673cae
FG
11056 (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x002FUL,
11057 (duk_uint16_t) 0x003AUL, (duk_uint16_t) 0xFFFFUL,
11058};
11fdf7f2 11059DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_white[24] = {
7c673cae
FG
11060 (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x0008UL,
11061 (duk_uint16_t) 0x000EUL, (duk_uint16_t) 0x001FUL,
11062 (duk_uint16_t) 0x0021UL, (duk_uint16_t) 0x009FUL,
11063 (duk_uint16_t) 0x00A1UL, (duk_uint16_t) 0x167FUL,
11064 (duk_uint16_t) 0x1681UL, (duk_uint16_t) 0x180DUL,
11065 (duk_uint16_t) 0x180FUL, (duk_uint16_t) 0x1FFFUL,
11066 (duk_uint16_t) 0x200BUL, (duk_uint16_t) 0x2027UL,
11067 (duk_uint16_t) 0x202AUL, (duk_uint16_t) 0x202EUL,
11068 (duk_uint16_t) 0x2030UL, (duk_uint16_t) 0x205EUL,
11069 (duk_uint16_t) 0x2060UL, (duk_uint16_t) 0x2FFFUL,
11070 (duk_uint16_t) 0x3001UL, (duk_uint16_t) 0xFEFEUL,
11071 (duk_uint16_t) 0xFF00UL, (duk_uint16_t) 0xFFFFUL,
11072};
11fdf7f2 11073DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_wordchar[10] = {
7c673cae
FG
11074 (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x002FUL,
11075 (duk_uint16_t) 0x003AUL, (duk_uint16_t) 0x0040UL,
11076 (duk_uint16_t) 0x005BUL, (duk_uint16_t) 0x005EUL,
11077 (duk_uint16_t) 0x0060UL, (duk_uint16_t) 0x0060UL,
11078 (duk_uint16_t) 0x007BUL, (duk_uint16_t) 0xFFFFUL,
11079};
11080
11081#endif /* DUK_USE_REGEXP_SUPPORT */
7c673cae
FG
11082/*
11083 * Misc util stuff
11084 */
11085
11086/* include removed: duk_internal.h */
11087
11088/*
11089 * Lowercase digits for radix values 2 to 36. Also doubles as lowercase
11090 * hex nybble table.
11091 */
11092
11fdf7f2
TL
11093DUK_INTERNAL const duk_uint8_t duk_lc_digits[36] = {
11094 DUK_ASC_0, DUK_ASC_1, DUK_ASC_2, DUK_ASC_3,
11095 DUK_ASC_4, DUK_ASC_5, DUK_ASC_6, DUK_ASC_7,
11096 DUK_ASC_8, DUK_ASC_9, DUK_ASC_LC_A, DUK_ASC_LC_B,
11097 DUK_ASC_LC_C, DUK_ASC_LC_D, DUK_ASC_LC_E, DUK_ASC_LC_F,
11098 DUK_ASC_LC_G, DUK_ASC_LC_H, DUK_ASC_LC_I, DUK_ASC_LC_J,
11099 DUK_ASC_LC_K, DUK_ASC_LC_L, DUK_ASC_LC_M, DUK_ASC_LC_N,
11100 DUK_ASC_LC_O, DUK_ASC_LC_P, DUK_ASC_LC_Q, DUK_ASC_LC_R,
11101 DUK_ASC_LC_S, DUK_ASC_LC_T, DUK_ASC_LC_U, DUK_ASC_LC_V,
11102 DUK_ASC_LC_W, DUK_ASC_LC_X, DUK_ASC_LC_Y, DUK_ASC_LC_Z
7c673cae
FG
11103};
11104
11fdf7f2
TL
11105DUK_INTERNAL const duk_uint8_t duk_uc_nybbles[16] = {
11106 DUK_ASC_0, DUK_ASC_1, DUK_ASC_2, DUK_ASC_3,
11107 DUK_ASC_4, DUK_ASC_5, DUK_ASC_6, DUK_ASC_7,
11108 DUK_ASC_8, DUK_ASC_9, DUK_ASC_UC_A, DUK_ASC_UC_B,
11109 DUK_ASC_UC_C, DUK_ASC_UC_D, DUK_ASC_UC_E, DUK_ASC_UC_F
7c673cae
FG
11110};
11111
11112/*
11fdf7f2 11113 * Table for hex decoding ASCII hex digits
7c673cae
FG
11114 */
11115
11fdf7f2
TL
11116DUK_INTERNAL const duk_int8_t duk_hex_dectab[256] = {
11117 /* -1 if invalid */
7c673cae
FG
11118 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0f */
11119 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1f */
11120 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x20-0x2f */
11121 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0x30-0x3f */
11122 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x40-0x4f */
11123 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x50-0x5f */
11124 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x60-0x6f */
11125 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x70-0x7f */
11126 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80-0x8f */
11127 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90-0x9f */
11128 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xa0-0xaf */
11129 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb0-0xbf */
11130 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc0-0xcf */
11131 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xd0-0xdf */
11132 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0-0xef */
11133 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0-0xff */
11134};
11135
11fdf7f2
TL
11136#if defined(DUK_USE_HEX_FASTPATH)
11137/* Preshifted << 4. Must use 16-bit entry to allow negative value signaling. */
11138DUK_INTERNAL const duk_int16_t duk_hex_dectab_shift4[256] = {
11139 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0f */
11140 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1f */
11141 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x20-0x2f */
11142 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, -1, -1, -1, -1, -1, -1, /* 0x30-0x3f */
11143 -1, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x40-0x4f */
11144 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x50-0x5f */
11145 -1, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x60-0x6f */
11146 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x70-0x7f */
11147 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80-0x8f */
11148 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90-0x9f */
11149 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xa0-0xaf */
11150 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb0-0xbf */
11151 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc0-0xcf */
11152 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xd0-0xdf */
11153 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0-0xef */
11154 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0-0xff */
11155};
11156#endif
11157
11158/*
11159 * Table for hex encoding bytes
11160 */
11161
11162#if defined(DUK_USE_HEX_FASTPATH)
11163/* Lookup to encode one byte directly into 2 characters:
11164 *
11165 * def genhextab(bswap):
11166 * for i in xrange(256):
11167 * t = chr(i).encode('hex')
11168 * if bswap:
11169 * t = t[1] + t[0]
11170 * print('0x' + t.encode('hex') + 'U')
11171 * print('big endian'); genhextab(False)
11172 * print('little endian'); genhextab(True)
11173*/
11174DUK_INTERNAL const duk_uint16_t duk_hex_enctab[256] = {
11175#if defined(DUK_USE_INTEGER_BE)
11176 0x3030U, 0x3031U, 0x3032U, 0x3033U, 0x3034U, 0x3035U, 0x3036U, 0x3037U,
11177 0x3038U, 0x3039U, 0x3061U, 0x3062U, 0x3063U, 0x3064U, 0x3065U, 0x3066U,
11178 0x3130U, 0x3131U, 0x3132U, 0x3133U, 0x3134U, 0x3135U, 0x3136U, 0x3137U,
11179 0x3138U, 0x3139U, 0x3161U, 0x3162U, 0x3163U, 0x3164U, 0x3165U, 0x3166U,
11180 0x3230U, 0x3231U, 0x3232U, 0x3233U, 0x3234U, 0x3235U, 0x3236U, 0x3237U,
11181 0x3238U, 0x3239U, 0x3261U, 0x3262U, 0x3263U, 0x3264U, 0x3265U, 0x3266U,
11182 0x3330U, 0x3331U, 0x3332U, 0x3333U, 0x3334U, 0x3335U, 0x3336U, 0x3337U,
11183 0x3338U, 0x3339U, 0x3361U, 0x3362U, 0x3363U, 0x3364U, 0x3365U, 0x3366U,
11184 0x3430U, 0x3431U, 0x3432U, 0x3433U, 0x3434U, 0x3435U, 0x3436U, 0x3437U,
11185 0x3438U, 0x3439U, 0x3461U, 0x3462U, 0x3463U, 0x3464U, 0x3465U, 0x3466U,
11186 0x3530U, 0x3531U, 0x3532U, 0x3533U, 0x3534U, 0x3535U, 0x3536U, 0x3537U,
11187 0x3538U, 0x3539U, 0x3561U, 0x3562U, 0x3563U, 0x3564U, 0x3565U, 0x3566U,
11188 0x3630U, 0x3631U, 0x3632U, 0x3633U, 0x3634U, 0x3635U, 0x3636U, 0x3637U,
11189 0x3638U, 0x3639U, 0x3661U, 0x3662U, 0x3663U, 0x3664U, 0x3665U, 0x3666U,
11190 0x3730U, 0x3731U, 0x3732U, 0x3733U, 0x3734U, 0x3735U, 0x3736U, 0x3737U,
11191 0x3738U, 0x3739U, 0x3761U, 0x3762U, 0x3763U, 0x3764U, 0x3765U, 0x3766U,
11192 0x3830U, 0x3831U, 0x3832U, 0x3833U, 0x3834U, 0x3835U, 0x3836U, 0x3837U,
11193 0x3838U, 0x3839U, 0x3861U, 0x3862U, 0x3863U, 0x3864U, 0x3865U, 0x3866U,
11194 0x3930U, 0x3931U, 0x3932U, 0x3933U, 0x3934U, 0x3935U, 0x3936U, 0x3937U,
11195 0x3938U, 0x3939U, 0x3961U, 0x3962U, 0x3963U, 0x3964U, 0x3965U, 0x3966U,
11196 0x6130U, 0x6131U, 0x6132U, 0x6133U, 0x6134U, 0x6135U, 0x6136U, 0x6137U,
11197 0x6138U, 0x6139U, 0x6161U, 0x6162U, 0x6163U, 0x6164U, 0x6165U, 0x6166U,
11198 0x6230U, 0x6231U, 0x6232U, 0x6233U, 0x6234U, 0x6235U, 0x6236U, 0x6237U,
11199 0x6238U, 0x6239U, 0x6261U, 0x6262U, 0x6263U, 0x6264U, 0x6265U, 0x6266U,
11200 0x6330U, 0x6331U, 0x6332U, 0x6333U, 0x6334U, 0x6335U, 0x6336U, 0x6337U,
11201 0x6338U, 0x6339U, 0x6361U, 0x6362U, 0x6363U, 0x6364U, 0x6365U, 0x6366U,
11202 0x6430U, 0x6431U, 0x6432U, 0x6433U, 0x6434U, 0x6435U, 0x6436U, 0x6437U,
11203 0x6438U, 0x6439U, 0x6461U, 0x6462U, 0x6463U, 0x6464U, 0x6465U, 0x6466U,
11204 0x6530U, 0x6531U, 0x6532U, 0x6533U, 0x6534U, 0x6535U, 0x6536U, 0x6537U,
11205 0x6538U, 0x6539U, 0x6561U, 0x6562U, 0x6563U, 0x6564U, 0x6565U, 0x6566U,
11206 0x6630U, 0x6631U, 0x6632U, 0x6633U, 0x6634U, 0x6635U, 0x6636U, 0x6637U,
11207 0x6638U, 0x6639U, 0x6661U, 0x6662U, 0x6663U, 0x6664U, 0x6665U, 0x6666U
11208#else /* DUK_USE_INTEGER_BE */
11209 0x3030U, 0x3130U, 0x3230U, 0x3330U, 0x3430U, 0x3530U, 0x3630U, 0x3730U,
11210 0x3830U, 0x3930U, 0x6130U, 0x6230U, 0x6330U, 0x6430U, 0x6530U, 0x6630U,
11211 0x3031U, 0x3131U, 0x3231U, 0x3331U, 0x3431U, 0x3531U, 0x3631U, 0x3731U,
11212 0x3831U, 0x3931U, 0x6131U, 0x6231U, 0x6331U, 0x6431U, 0x6531U, 0x6631U,
11213 0x3032U, 0x3132U, 0x3232U, 0x3332U, 0x3432U, 0x3532U, 0x3632U, 0x3732U,
11214 0x3832U, 0x3932U, 0x6132U, 0x6232U, 0x6332U, 0x6432U, 0x6532U, 0x6632U,
11215 0x3033U, 0x3133U, 0x3233U, 0x3333U, 0x3433U, 0x3533U, 0x3633U, 0x3733U,
11216 0x3833U, 0x3933U, 0x6133U, 0x6233U, 0x6333U, 0x6433U, 0x6533U, 0x6633U,
11217 0x3034U, 0x3134U, 0x3234U, 0x3334U, 0x3434U, 0x3534U, 0x3634U, 0x3734U,
11218 0x3834U, 0x3934U, 0x6134U, 0x6234U, 0x6334U, 0x6434U, 0x6534U, 0x6634U,
11219 0x3035U, 0x3135U, 0x3235U, 0x3335U, 0x3435U, 0x3535U, 0x3635U, 0x3735U,
11220 0x3835U, 0x3935U, 0x6135U, 0x6235U, 0x6335U, 0x6435U, 0x6535U, 0x6635U,
11221 0x3036U, 0x3136U, 0x3236U, 0x3336U, 0x3436U, 0x3536U, 0x3636U, 0x3736U,
11222 0x3836U, 0x3936U, 0x6136U, 0x6236U, 0x6336U, 0x6436U, 0x6536U, 0x6636U,
11223 0x3037U, 0x3137U, 0x3237U, 0x3337U, 0x3437U, 0x3537U, 0x3637U, 0x3737U,
11224 0x3837U, 0x3937U, 0x6137U, 0x6237U, 0x6337U, 0x6437U, 0x6537U, 0x6637U,
11225 0x3038U, 0x3138U, 0x3238U, 0x3338U, 0x3438U, 0x3538U, 0x3638U, 0x3738U,
11226 0x3838U, 0x3938U, 0x6138U, 0x6238U, 0x6338U, 0x6438U, 0x6538U, 0x6638U,
11227 0x3039U, 0x3139U, 0x3239U, 0x3339U, 0x3439U, 0x3539U, 0x3639U, 0x3739U,
11228 0x3839U, 0x3939U, 0x6139U, 0x6239U, 0x6339U, 0x6439U, 0x6539U, 0x6639U,
11229 0x3061U, 0x3161U, 0x3261U, 0x3361U, 0x3461U, 0x3561U, 0x3661U, 0x3761U,
11230 0x3861U, 0x3961U, 0x6161U, 0x6261U, 0x6361U, 0x6461U, 0x6561U, 0x6661U,
11231 0x3062U, 0x3162U, 0x3262U, 0x3362U, 0x3462U, 0x3562U, 0x3662U, 0x3762U,
11232 0x3862U, 0x3962U, 0x6162U, 0x6262U, 0x6362U, 0x6462U, 0x6562U, 0x6662U,
11233 0x3063U, 0x3163U, 0x3263U, 0x3363U, 0x3463U, 0x3563U, 0x3663U, 0x3763U,
11234 0x3863U, 0x3963U, 0x6163U, 0x6263U, 0x6363U, 0x6463U, 0x6563U, 0x6663U,
11235 0x3064U, 0x3164U, 0x3264U, 0x3364U, 0x3464U, 0x3564U, 0x3664U, 0x3764U,
11236 0x3864U, 0x3964U, 0x6164U, 0x6264U, 0x6364U, 0x6464U, 0x6564U, 0x6664U,
11237 0x3065U, 0x3165U, 0x3265U, 0x3365U, 0x3465U, 0x3565U, 0x3665U, 0x3765U,
11238 0x3865U, 0x3965U, 0x6165U, 0x6265U, 0x6365U, 0x6465U, 0x6565U, 0x6665U,
11239 0x3066U, 0x3166U, 0x3266U, 0x3366U, 0x3466U, 0x3566U, 0x3666U, 0x3766U,
11240 0x3866U, 0x3966U, 0x6166U, 0x6266U, 0x6366U, 0x6466U, 0x6566U, 0x6666U
11241#endif /* DUK_USE_INTEGER_BE */
11242};
11243#endif /* DUK_USE_HEX_FASTPATH */
11244
11245/*
11246 * Table for base-64 encoding
11247 */
11248
11249#if defined(DUK_USE_BASE64_FASTPATH)
11250DUK_INTERNAL const duk_uint8_t duk_base64_enctab[64] = {
11251 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, /* A...P */
11252 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, /* Q...f */
11253 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, /* g...v */
11254 0x77, 0x78, 0x79, 0x7a, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f /* w.../ */
11255};
11256#endif /* DUK_USE_BASE64_FASTPATH */
11257
11258/*
11259 * Table for base-64 decoding
11260 */
11261
11262#if defined(DUK_USE_BASE64_FASTPATH)
11263DUK_INTERNAL const duk_int8_t duk_base64_dectab[256] = {
11264 /* -1 = error, -2 = allowed whitespace, -3 = padding ('='), 0...63 decoded bytes */
11265 -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -1, -1, -2, -1, -1, /* 0x00...0x0f */
11266 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10...0x1f */
11267 -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20...0x2f */
11268 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -3, -1, -1, /* 0x30...0x3f */
11269 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40...0x4f */
11270 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50...0x5f */
11271 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60...0x6f */
11272 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 0x70...0x7f */
11273 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80...0x8f */
11274 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90...0x9f */
11275 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xa0...0xaf */
11276 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb0...0xbf */
11277 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc0...0xcf */
11278 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xd0...0xdf */
11279 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0...0xef */
11280 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0...0xff */
11281};
11282#endif /* DUK_USE_BASE64_FASTPATH */
11283
7c673cae
FG
11284/*
11285 * Arbitrary byteswap for potentially unaligned values
11286 *
11287 * Used to byteswap pointers e.g. in debugger code.
11288 */
11289
11290#if defined(DUK_USE_DEBUGGER_SUPPORT) /* For now only needed by the debugger. */
11291DUK_INTERNAL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len) {
11292 duk_uint8_t tmp;
11293 duk_uint8_t *q = p + len - 1;
11294
11295 while (p - q < 0) {
11296 tmp = *p;
11297 *p = *q;
11298 *q = tmp;
11299 p++;
11300 q--;
11301 }
11302}
11303#endif
7c673cae
FG
11304/*
11305 * Round a number upwards to a prime (not usually the nearest one).
11306 *
11307 * Uses a table of successive 32-bit primes whose ratio is roughly
11308 * constant. This keeps the relative upwards 'rounding error' bounded
11309 * and the data size small. A simple 'predict-correct' compression is
11310 * used to compress primes to one byte per prime. See genhashsizes.py
11311 * for details.
11312 *
11313 * The minimum prime returned here must be coordinated with the possible
11314 * probe sequence steps in duk_hobject and duk_heap stringtable.
11315 */
11316
11317/* include removed: duk_internal.h */
11318
11319/* Awkward inclusion condition: drop out of compilation if not needed by any
11320 * call site: object hash part or probing stringtable.
11321 */
11322#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE)
11323
11324/* hash size ratio goal, must match genhashsizes.py */
11325#define DUK__HASH_SIZE_RATIO 1177 /* floor(1.15 * (1 << 10)) */
11326
11327/* prediction corrections for prime list (see genhashsizes.py) */
11328DUK_LOCAL const duk_int8_t duk__hash_size_corrections[] = {
11329 17, /* minimum prime */
11330 4, 3, 4, 1, 4, 1, 1, 2, 2, 2, 2, 1, 6, 6, 9, 5, 1, 2, 2, 5, 1, 3, 3, 3,
11331 5, 4, 4, 2, 4, 8, 3, 4, 23, 2, 4, 7, 8, 11, 2, 12, 15, 10, 1, 1, 5, 1, 5,
11332 8, 9, 17, 14, 10, 7, 5, 2, 46, 21, 1, 9, 9, 4, 4, 10, 23, 36, 6, 20, 29,
11333 18, 6, 19, 21, 16, 11, 5, 5, 48, 9, 1, 39, 14, 8, 4, 29, 9, 1, 15, 48, 12,
11334 22, 6, 15, 27, 4, 2, 17, 28, 8, 9, 4, 5, 8, 3, 3, 8, 37, 11, 15, 8, 30,
11335 43, 6, 33, 41, 5, 20, 32, 41, 38, 24, 77, 14, 19, 11, 4, 35, 18, 19, 41,
11336 10, 23, 16, 9, 2,
11337 -1
11338};
11339
11340/* probe steps (see genhashsizes.py), currently assumed to be 32 entries long
11341 * (DUK_UTIL_GET_HASH_PROBE_STEP macro).
11342 */
11343DUK_INTERNAL duk_uint8_t duk_util_probe_steps[32] = {
11344 2, 3, 5, 7, 11, 13, 19, 31, 41, 47, 59, 67, 73, 79, 89, 101, 103, 107,
11345 109, 127, 137, 139, 149, 157, 163, 167, 173, 181, 191, 193, 197, 199
11346};
11347
11348DUK_INTERNAL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size) {
11349 const duk_int8_t *p = duk__hash_size_corrections;
11350 duk_uint32_t curr;
11351
11352 curr = (duk_uint32_t) *p++;
11353 for (;;) {
11354 duk_small_int_t t = (duk_small_int_t) *p++;
11355 if (t < 0) {
11356 /* may happen if size is very close to 2^32-1 */
11357 break;
11358 }
11359
11360 /* prediction: portable variant using doubles if 64-bit values not available */
11361#ifdef DUK_USE_64BIT_OPS
11362 curr = (duk_uint32_t) ((((duk_uint64_t) curr) * ((duk_uint64_t) DUK__HASH_SIZE_RATIO)) >> 10);
11363#else
11364 /* 32-bit x 11-bit = 43-bit, fits accurately into a double */
11365 curr = (duk_uint32_t) DUK_FLOOR(((double) curr) * ((double) DUK__HASH_SIZE_RATIO) / 1024.0);
11366#endif
11367
11368 /* correction */
11369 curr += t;
11370
11371 DUK_DDD(DUK_DDDPRINT("size=%ld, curr=%ld", (long) size, (long) curr));
11372
11373 if (curr >= size) {
11374 return curr;
11375 }
11376 }
11377 return 0;
11378}
11379
11380#endif /* DUK_USE_HOBJECT_HASH_PART || DUK_USE_STRTAB_PROBE */
7c673cae
FG
11381/*
11382 * Hobject Ecmascript [[Class]].
11383 */
11384
11385/* include removed: duk_internal.h */
11386
11387#if (DUK_STRIDX_UC_ARGUMENTS > 255)
11388#error constant too large
11389#endif
11390#if (DUK_STRIDX_ARRAY > 255)
11391#error constant too large
11392#endif
11393#if (DUK_STRIDX_UC_BOOLEAN > 255)
11394#error constant too large
11395#endif
11396#if (DUK_STRIDX_DATE > 255)
11397#error constant too large
11398#endif
11399#if (DUK_STRIDX_UC_ERROR > 255)
11400#error constant too large
11401#endif
11402#if (DUK_STRIDX_UC_FUNCTION > 255)
11403#error constant too large
11404#endif
11405#if (DUK_STRIDX_JSON > 255)
11406#error constant too large
11407#endif
11408#if (DUK_STRIDX_MATH > 255)
11409#error constant too large
11410#endif
11411#if (DUK_STRIDX_UC_NUMBER > 255)
11412#error constant too large
11413#endif
11414#if (DUK_STRIDX_UC_OBJECT > 255)
11415#error constant too large
11416#endif
11417#if (DUK_STRIDX_REG_EXP > 255)
11418#error constant too large
11419#endif
11420#if (DUK_STRIDX_UC_STRING > 255)
11421#error constant too large
11422#endif
11423#if (DUK_STRIDX_GLOBAL > 255)
11424#error constant too large
11425#endif
11426#if (DUK_STRIDX_OBJ_ENV > 255)
11427#error constant too large
11428#endif
11429#if (DUK_STRIDX_DEC_ENV > 255)
11430#error constant too large
11431#endif
11432#if (DUK_STRIDX_UC_BUFFER > 255)
11433#error constant too large
11434#endif
11435#if (DUK_STRIDX_UC_POINTER > 255)
11436#error constant too large
11437#endif
11438#if (DUK_STRIDX_UC_THREAD > 255)
11439#error constant too large
11440#endif
11441#if (DUK_STRIDX_ARRAY_BUFFER > 255)
11442#error constant too large
11443#endif
11444#if (DUK_STRIDX_DATA_VIEW > 255)
11445#error constant too large
11446#endif
11447#if (DUK_STRIDX_INT8_ARRAY > 255)
11448#error constant too large
11449#endif
11450#if (DUK_STRIDX_UINT8_ARRAY > 255)
11451#error constant too large
11452#endif
11453#if (DUK_STRIDX_UINT8_CLAMPED_ARRAY > 255)
11454#error constant too large
11455#endif
11456#if (DUK_STRIDX_INT16_ARRAY > 255)
11457#error constant too large
11458#endif
11459#if (DUK_STRIDX_UINT16_ARRAY > 255)
11460#error constant too large
11461#endif
11462#if (DUK_STRIDX_INT32_ARRAY > 255)
11463#error constant too large
11464#endif
11465#if (DUK_STRIDX_UINT32_ARRAY > 255)
11466#error constant too large
11467#endif
11468#if (DUK_STRIDX_FLOAT32_ARRAY > 255)
11469#error constant too large
11470#endif
11471#if (DUK_STRIDX_FLOAT64_ARRAY > 255)
11472#error constant too large
11473#endif
11474#if (DUK_STRIDX_EMPTY_STRING > 255)
11475#error constant too large
11476#endif
11477
11478/* Note: assumes that these string indexes are 8-bit, genstrings.py must ensure that */
11479DUK_INTERNAL duk_uint8_t duk_class_number_to_stridx[32] = {
11480 DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */
11481 DUK_STRIDX_UC_ARGUMENTS,
11482 DUK_STRIDX_ARRAY,
11483 DUK_STRIDX_UC_BOOLEAN,
11484 DUK_STRIDX_DATE,
11485 DUK_STRIDX_UC_ERROR,
11486 DUK_STRIDX_UC_FUNCTION,
11487 DUK_STRIDX_JSON,
11488 DUK_STRIDX_MATH,
11489 DUK_STRIDX_UC_NUMBER,
11490 DUK_STRIDX_UC_OBJECT,
11491 DUK_STRIDX_REG_EXP,
11492 DUK_STRIDX_UC_STRING,
11493 DUK_STRIDX_GLOBAL,
11494 DUK_STRIDX_OBJ_ENV,
11495 DUK_STRIDX_DEC_ENV,
11496 DUK_STRIDX_UC_BUFFER,
11497 DUK_STRIDX_UC_POINTER,
11498 DUK_STRIDX_UC_THREAD,
11499 DUK_STRIDX_ARRAY_BUFFER,
11500 DUK_STRIDX_DATA_VIEW,
11501 DUK_STRIDX_INT8_ARRAY,
11502 DUK_STRIDX_UINT8_ARRAY,
11503 DUK_STRIDX_UINT8_CLAMPED_ARRAY,
11504 DUK_STRIDX_INT16_ARRAY,
11505 DUK_STRIDX_UINT16_ARRAY,
11506 DUK_STRIDX_INT32_ARRAY,
11507 DUK_STRIDX_UINT32_ARRAY,
11508 DUK_STRIDX_FLOAT32_ARRAY,
11509 DUK_STRIDX_FLOAT64_ARRAY,
11510 DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */
11511 DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */
11512};
7c673cae
FG
11513/*
11514 * Default allocation functions.
11515 *
11516 * Assumes behavior such as malloc allowing zero size, yielding
11517 * a NULL or a unique pointer which is a no-op for free.
11518 */
11519
11520/* include removed: duk_internal.h */
11521
11fdf7f2 11522#if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS)
7c673cae
FG
11523DUK_INTERNAL void *duk_default_alloc_function(void *udata, duk_size_t size) {
11524 void *res;
11525 DUK_UNREF(udata);
11526 res = DUK_ANSI_MALLOC(size);
11527 DUK_DDD(DUK_DDDPRINT("default alloc function: %lu -> %p",
11528 (unsigned long) size, (void *) res));
11529 return res;
11530}
11531
11532DUK_INTERNAL void *duk_default_realloc_function(void *udata, void *ptr, duk_size_t newsize) {
11533 void *res;
11534 DUK_UNREF(udata);
11535 res = DUK_ANSI_REALLOC(ptr, newsize);
11536 DUK_DDD(DUK_DDDPRINT("default realloc function: %p %lu -> %p",
11537 (void *) ptr, (unsigned long) newsize, (void *) res));
11538 return res;
11539}
11540
11541DUK_INTERNAL void duk_default_free_function(void *udata, void *ptr) {
11542 DUK_DDD(DUK_DDDPRINT("default free function: %p", (void *) ptr));
11543 DUK_UNREF(udata);
11544 DUK_ANSI_FREE(ptr);
11545}
11fdf7f2 11546#endif /* DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS */
7c673cae
FG
11547/*
11548 * Buffer
11549 */
11550
11551/* include removed: duk_internal.h */
11552
11553DUK_EXTERNAL void *duk_resize_buffer(duk_context *ctx, duk_idx_t index, duk_size_t new_size) {
11554 duk_hthread *thr = (duk_hthread *) ctx;
11555 duk_hbuffer_dynamic *h;
11556
11557 DUK_ASSERT_CTX_VALID(ctx);
11558
11559 h = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, index);
11560 DUK_ASSERT(h != NULL);
11561
11562 if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) {
11fdf7f2 11563 DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE);
7c673cae
FG
11564 }
11565
11566 /* maximum size check is handled by callee */
11567 duk_hbuffer_resize(thr, h, new_size);
11568
11569 return DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h);
11570}
11571
11572DUK_EXTERNAL void *duk_steal_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) {
11573 duk_hthread *thr = (duk_hthread *) ctx;
11574 duk_hbuffer_dynamic *h;
11575 void *ptr;
11576 duk_size_t sz;
11577
11578 DUK_ASSERT(ctx != NULL);
11579
11580 h = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, index);
11581 DUK_ASSERT(h != NULL);
11582
11583 if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) {
11fdf7f2 11584 DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE);
7c673cae
FG
11585 }
11586
11587 /* Forget the previous allocation, setting size to 0 and alloc to
11588 * NULL. Caller is responsible for freeing the previous allocation.
11589 * Getting the allocation and clearing it is done in the same API
11590 * call to avoid any chance of a realloc.
11591 */
11592 ptr = DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h);
11593 sz = DUK_HBUFFER_DYNAMIC_GET_SIZE(h);
11594 if (out_size) {
11595 *out_size = sz;
11596 }
11597 DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(thr->heap, h);
11598 DUK_HBUFFER_DYNAMIC_SET_SIZE(h, 0);
11599
11600 return ptr;
11601}
11602
11603DUK_EXTERNAL void duk_config_buffer(duk_context *ctx, duk_idx_t index, void *ptr, duk_size_t len) {
11604 duk_hthread *thr = (duk_hthread *) ctx;
11605 duk_hbuffer_external *h;
11606
11607 DUK_ASSERT(ctx != NULL);
11608
11609 h = (duk_hbuffer_external *) duk_require_hbuffer(ctx, index);
11610 DUK_ASSERT(h != NULL);
11611
11612 if (!DUK_HBUFFER_HAS_EXTERNAL(h)) {
11fdf7f2 11613 DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE);
7c673cae
FG
11614 }
11615 DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h));
11616
11617 DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(thr->heap, h, ptr);
11618 DUK_HBUFFER_EXTERNAL_SET_SIZE(h, len);
11619}
7c673cae
FG
11620/*
11621 * Bytecode dump/load
11622 *
11623 * The bytecode load primitive is more important performance-wise than the
11624 * dump primitive.
11625 *
11626 * Unlike most Duktape API calls, bytecode dump/load is not guaranteed to be
11627 * memory safe for invalid arguments - caller beware! There's little point
11628 * in trying to achieve memory safety unless bytecode instructions are also
11629 * validated which is not easy to do with indirect register references etc.
11630 */
11631
11632/* include removed: duk_internal.h */
11633
11634#if defined(DUK_USE_BYTECODE_DUMP_SUPPORT)
11635
11636#define DUK__SER_MARKER 0xff
11637#define DUK__SER_VERSION 0x00
11638#define DUK__SER_STRING 0x00
11639#define DUK__SER_NUMBER 0x01
11640#define DUK__BYTECODE_INITIAL_ALLOC 256
11641
11642/*
11643 * Dump/load helpers, xxx_raw() helpers do no buffer checks
11644 */
11645
11646DUK_LOCAL duk_uint8_t *duk__load_string_raw(duk_context *ctx, duk_uint8_t *p) {
11647 duk_uint32_t len;
11648
11649 len = DUK_RAW_READ_U32_BE(p);
11650 duk_push_lstring(ctx, (const char *) p, len);
11651 p += len;
11652 return p;
11653}
11654
11655DUK_LOCAL duk_uint8_t *duk__load_buffer_raw(duk_context *ctx, duk_uint8_t *p) {
11656 duk_uint32_t len;
11657 duk_uint8_t *buf;
11658
11659 len = DUK_RAW_READ_U32_BE(p);
11660 buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len);
11661 DUK_ASSERT(buf != NULL);
11662 DUK_MEMCPY((void *) buf, (const void *) p, (size_t) len);
11663 p += len;
11664 return p;
11665}
11666
11667DUK_LOCAL duk_uint8_t *duk__dump_hstring_raw(duk_uint8_t *p, duk_hstring *h) {
11668 duk_size_t len;
11669 duk_uint32_t tmp32;
11670
11671 DUK_ASSERT(h != NULL);
11672
11673 len = DUK_HSTRING_GET_BYTELEN(h);
11674 DUK_ASSERT(len <= 0xffffffffUL); /* string limits */
11675 tmp32 = (duk_uint32_t) len;
11676 DUK_RAW_WRITE_U32_BE(p, tmp32);
11677 DUK_MEMCPY((void *) p,
11678 (const void *) DUK_HSTRING_GET_DATA(h),
11679 len);
11680 p += len;
11681 return p;
11682}
11683
11684DUK_LOCAL duk_uint8_t *duk__dump_hbuffer_raw(duk_hthread *thr, duk_uint8_t *p, duk_hbuffer *h) {
11685 duk_size_t len;
11686 duk_uint32_t tmp32;
11687
11688 DUK_ASSERT(thr != NULL);
11689 DUK_ASSERT(h != NULL);
11690 DUK_UNREF(thr);
11691
11692 len = DUK_HBUFFER_GET_SIZE(h);
11693 DUK_ASSERT(len <= 0xffffffffUL); /* buffer limits */
11694 tmp32 = (duk_uint32_t) len;
11695 DUK_RAW_WRITE_U32_BE(p, tmp32);
11696 DUK_MEMCPY((void *) p,
11697 (const void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h),
11698 len);
11699 p += len;
11700 return p;
11701}
11702
11703DUK_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) {
11704 duk_hstring *h_str;
11705 duk_tval *tv;
11706
11707 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_GET_STRING(thr, stridx));
11708 if (tv != NULL && DUK_TVAL_IS_STRING(tv)) {
11709 h_str = DUK_TVAL_GET_STRING(tv);
11710 DUK_ASSERT(h_str != NULL);
11711 } else {
11712 h_str = DUK_HTHREAD_STRING_EMPTY_STRING(thr);
11713 DUK_ASSERT(h_str != NULL);
11714 }
11715 DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
11716 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(h_str), p);
11717 p = duk__dump_hstring_raw(p, h_str);
11718 return p;
11719}
11720
11721DUK_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) {
11722 duk_tval *tv;
11723
11724 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_GET_STRING(thr, stridx));
11725 if (tv != NULL && DUK_TVAL_IS_BUFFER(tv)) {
11726 duk_hbuffer *h_buf;
11727 h_buf = DUK_TVAL_GET_BUFFER(tv);
11728 DUK_ASSERT(h_buf != NULL);
11729 DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
11730 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HBUFFER_GET_SIZE(h_buf), p);
11731 p = duk__dump_hbuffer_raw(thr, p, h_buf);
11732 } else {
11733 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
11734 DUK_RAW_WRITE_U32_BE(p, 0);
11735 }
11736 return p;
11737}
11738
11739DUK_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) {
11740 duk_tval *tv;
11741 duk_uint32_t val;
11742
11743 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_GET_STRING(thr, stridx));
11744 if (tv != NULL && DUK_TVAL_IS_NUMBER(tv)) {
11745 val = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv);
11746 } else {
11747 val = def_value;
11748 }
11749 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
11750 DUK_RAW_WRITE_U32_BE(p, val);
11751 return p;
11752}
11753
11754DUK_LOCAL duk_uint8_t *duk__dump_varmap(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func) {
11755 duk_tval *tv;
11756
11757 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_STRING_INT_VARMAP(thr));
11758 if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) {
11759 duk_hobject *h;
11760 duk_uint_fast32_t i;
11761
11762 h = DUK_TVAL_GET_OBJECT(tv);
11763 DUK_ASSERT(h != NULL);
11764
11765 /* We know _Varmap only has own properties so walk property
11766 * table directly. We also know _Varmap is dense and all
11767 * values are numbers; assert for these. GC and finalizers
11768 * shouldn't affect _Varmap so side effects should be fine.
11769 */
11770 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) {
11771 duk_hstring *key;
11772 duk_tval *tv_val;
11773 duk_uint32_t val;
11774
11775 key = DUK_HOBJECT_E_GET_KEY(thr->heap, h, i);
11776 DUK_ASSERT(key != NULL); /* _Varmap is dense */
11777 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, h, i));
11778 tv_val = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, h, i);
11779 DUK_ASSERT(tv_val != NULL);
11780 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_val)); /* known to be number; in fact an integer */
11781#if defined(DUK_USE_FASTINT)
11782 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv_val));
11783 DUK_ASSERT(DUK_TVAL_GET_FASTINT(tv_val) == (duk_int64_t) DUK_TVAL_GET_FASTINT_U32(tv_val)); /* known to be 32-bit */
11784 val = DUK_TVAL_GET_FASTINT_U32(tv_val);
11785#else
11786 val = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv_val);
11787#endif
11788
11789 DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
11790 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(key) + 4, p);
11791 p = duk__dump_hstring_raw(p, key);
11792 DUK_RAW_WRITE_U32_BE(p, val);
11793 }
11794 }
11795 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
11796 DUK_RAW_WRITE_U32_BE(p, 0); /* end of _Varmap */
11797 return p;
11798}
11799
11800DUK_LOCAL duk_uint8_t *duk__dump_formals(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func) {
11801 duk_tval *tv;
11802
11803 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_STRING_INT_FORMALS(thr));
11804 if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) {
11805 duk_hobject *h;
11806 duk_uint_fast32_t i;
11807
11808 h = DUK_TVAL_GET_OBJECT(tv);
11809 DUK_ASSERT(h != NULL);
11810
11811 /* We know _Formals is dense and all entries will be in the
11812 * array part. GC and finalizers shouldn't affect _Formals
11813 * so side effects should be fine.
11814 */
11815 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) {
11816 duk_tval *tv_val;
11817 duk_hstring *varname;
11818
11819 tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, h, i);
11820 DUK_ASSERT(tv_val != NULL);
11821 if (DUK_TVAL_IS_STRING(tv_val)) {
11822 /* Array is dense and contains only strings, but ASIZE may
11823 * be larger than used part and there are UNUSED entries.
11824 */
11825 varname = DUK_TVAL_GET_STRING(tv_val);
11826 DUK_ASSERT(varname != NULL);
11827
11828 DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
11829 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(varname), p);
11830 p = duk__dump_hstring_raw(p, varname);
11831 }
11832 }
11833 }
11834 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
11835 DUK_RAW_WRITE_U32_BE(p, 0); /* end of _Formals */
11836 return p;
11837}
11838
11839static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func, duk_bufwriter_ctx *bw_ctx, duk_uint8_t *p) {
11840 duk_hthread *thr;
11841 duk_tval *tv, *tv_end;
11842 duk_instr_t *ins, *ins_end;
11843 duk_hobject **fn, **fn_end;
11844 duk_hstring *h_str;
11845 duk_uint32_t count_instr;
11846 duk_uint32_t tmp32;
11847 duk_uint16_t tmp16;
11848 duk_double_t d;
11849
11850 thr = (duk_hthread *) ctx;
11851 DUK_UNREF(ctx);
11852 DUK_UNREF(thr);
11853
11854 DUK_DD(DUK_DDPRINT("dumping function %p to %p: "
11855 "consts=[%p,%p[ (%ld bytes, %ld items), "
11856 "funcs=[%p,%p[ (%ld bytes, %ld items), "
11857 "code=[%p,%p[ (%ld bytes, %ld items)",
11858 (void *) func,
11859 (void *) p,
11860 (void *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, func),
11861 (void *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, func),
11862 (long) DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE(thr->heap, func),
11863 (long) DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(thr->heap, func),
11864 (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, func),
11865 (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, func),
11866 (long) DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE(thr->heap, func),
11867 (long) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(thr->heap, func),
11868 (void *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, func),
11869 (void *) DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr->heap, func),
11870 (long) DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE(thr->heap, func),
11871 (long) DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(thr->heap, func)));
11872
11873 DUK_ASSERT(DUK_USE_ESBC_MAX_BYTES <= 0x7fffffffUL); /* ensures no overflow */
11874 count_instr = (duk_uint32_t) DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(thr->heap, func);
11875 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 3 * 4 + 2 * 2 + 3 * 4 + count_instr * 4, p);
11876
11877 /* Fixed header info. */
11878 tmp32 = count_instr;
11879 DUK_RAW_WRITE_U32_BE(p, tmp32);
11880 tmp32 = (duk_uint32_t) DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(thr->heap, func);
11881 DUK_RAW_WRITE_U32_BE(p, tmp32);
11882 tmp32 = (duk_uint32_t) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(thr->heap, func);
11883 DUK_RAW_WRITE_U32_BE(p, tmp32);
11884 tmp16 = func->nregs;
11885 DUK_RAW_WRITE_U16_BE(p, tmp16);
11886 tmp16 = func->nargs;
11887 DUK_RAW_WRITE_U16_BE(p, tmp16);
11888#if defined(DUK_USE_DEBUGGER_SUPPORT)
11889 tmp32 = func->start_line;
11890 DUK_RAW_WRITE_U32_BE(p, tmp32);
11891 tmp32 = func->end_line;
11892 DUK_RAW_WRITE_U32_BE(p, tmp32);
11893#else
11894 DUK_RAW_WRITE_U32_BE(p, 0);
11895 DUK_RAW_WRITE_U32_BE(p, 0);
11896#endif
11897 tmp32 = ((duk_heaphdr *) func)->h_flags & DUK_HEAPHDR_FLAGS_FLAG_MASK;
11898 DUK_RAW_WRITE_U32_BE(p, tmp32);
11899
11900 /* Bytecode instructions: endian conversion needed unless
11901 * platform is big endian.
11902 */
11903 ins = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, func);
11904 ins_end = DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr->heap, func);
11905 DUK_ASSERT((duk_size_t) (ins_end - ins) == (duk_size_t) count_instr);
11906#if defined(DUK_USE_INTEGER_BE)
11907 DUK_MEMCPY((void *) p, (const void *) ins, (size_t) (ins_end - ins));
11908 p += (size_t) (ins_end - ins);
11909#else
11910 while (ins != ins_end) {
11911 tmp32 = (duk_uint32_t) (*ins);
11912 DUK_RAW_WRITE_U32_BE(p, tmp32);
11913 ins++;
11914 }
11915#endif
11916
11917 /* Constants: variable size encoding. */
11918 tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, func);
11919 tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, func);
11920 while (tv != tv_end) {
11921 /* constants are strings or numbers now */
11922 DUK_ASSERT(DUK_TVAL_IS_STRING(tv) ||
11923 DUK_TVAL_IS_NUMBER(tv));
11924
11925 if (DUK_TVAL_IS_STRING(tv)) {
11926 h_str = DUK_TVAL_GET_STRING(tv);
11927 DUK_ASSERT(h_str != NULL);
11928 DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
11929 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1 + 4 + DUK_HSTRING_GET_BYTELEN(h_str), p),
11930 *p++ = DUK__SER_STRING;
11931 p = duk__dump_hstring_raw(p, h_str);
11932 } else {
11933 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
11934 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1 + 8, p);
11935 *p++ = DUK__SER_NUMBER;
11936 d = DUK_TVAL_GET_NUMBER(tv);
11937 DUK_RAW_WRITE_DOUBLE_BE(p, d);
11938 }
11939 tv++;
11940 }
11941
11942 /* Inner functions recursively. */
11943 fn = (duk_hobject **) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, func);
11944 fn_end = (duk_hobject **) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, func);
11945 while (fn != fn_end) {
11946 /* XXX: This causes recursion up to inner function depth
11947 * which is normally not an issue, e.g. mark-and-sweep uses
11948 * a recursion limiter to avoid C stack issues. Avoiding
11949 * this would mean some sort of a work list or just refusing
11950 * to serialize deep functions.
11951 */
11952 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(*fn));
11953 p = duk__dump_func(ctx, (duk_hcompiledfunction *) *fn, bw_ctx, p);
11954 fn++;
11955 }
11956
11957 /* Object extra properties.
11958 *
11959 * There are some difference between function templates and functions.
11960 * For example, function templates don't have .length and nargs is
11961 * normally used to instantiate the functions.
11962 */
11963
11964 p = duk__dump_uint32_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_LENGTH, (duk_uint32_t) func->nargs);
11965 p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_NAME);
11966 p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_FILE_NAME);
11967 p = duk__dump_buffer_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_INT_PC2LINE);
11968 p = duk__dump_varmap(thr, p, bw_ctx, (duk_hobject *) func);
11969 p = duk__dump_formals(thr, p, bw_ctx, (duk_hobject *) func);
11970
11971 DUK_DD(DUK_DDPRINT("serialized function %p -> final pointer %p", (void *) func, (void *) p));
11972
11973 return p;
11974}
11975
11976/* Load a function from bytecode. The function object returned here must
11977 * match what is created by duk_js_push_closure() with respect to its flags,
11978 * properties, etc.
11979 *
11980 * NOTE: there are intentionally no input buffer length / bound checks.
11981 * Adding them would be easy but wouldn't ensure memory safety as untrusted
11982 * or broken bytecode is unsafe during execution unless the opcodes themselves
11983 * are validated (which is quite complex, especially for indirect opcodes).
11984 */
11985
11986#define DUK__ASSERT_LEFT(n) do { \
11987 DUK_ASSERT((duk_size_t) (p_end - p) >= (duk_size_t) (n)); \
11988 } while (0)
11989
11990static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t *p_end) {
11991 duk_hthread *thr;
11992 duk_hcompiledfunction *h_fun;
11993 duk_hbuffer *h_data;
11994 duk_size_t data_size;
11995 duk_uint32_t count_instr, count_const, count_funcs;
11996 duk_uint32_t n;
11997 duk_uint32_t tmp32;
11998 duk_small_uint_t const_type;
11999 duk_uint8_t *fun_data;
12000 duk_uint8_t *q;
12001 duk_idx_t idx_base;
12002 duk_tval *tv1;
12003 duk_uarridx_t arr_idx;
12004
12005 /* XXX: There's some overlap with duk_js_closure() here, but
12006 * seems difficult to share code. Ensure that the final function
12007 * looks the same as created by duk_js_closure().
12008 */
12009
12010 DUK_ASSERT(ctx != NULL);
12011 thr = (duk_hthread *) ctx;
12012
12013 DUK_DD(DUK_DDPRINT("loading function, p=%p, p_end=%p", (void *) p, (void *) p_end));
12014
12015 DUK__ASSERT_LEFT(3 * 4);
12016 count_instr = DUK_RAW_READ_U32_BE(p);
12017 count_const = DUK_RAW_READ_U32_BE(p);
12018 count_funcs = DUK_RAW_READ_U32_BE(p);
12019
12020 data_size = sizeof(duk_tval) * count_const +
12021 sizeof(duk_hobject *) * count_funcs +
12022 sizeof(duk_instr_t) * count_instr;
12023
12024 DUK_DD(DUK_DDPRINT("instr=%ld, const=%ld, funcs=%ld, data_size=%ld",
12025 (long) count_instr, (long) count_const,
12026 (long) count_const, (long) data_size));
12027
12028 /* Value stack is used to ensure reachability of constants and
12029 * inner functions being loaded. Require enough space to handle
12030 * large functions correctly.
12031 */
12032 duk_require_stack(ctx, 2 + count_const + count_funcs);
12033 idx_base = duk_get_top(ctx);
12034
12035 /* Push function object, init flags etc. This must match
12036 * duk_js_push_closure() quite carefully.
12037 */
12038 duk_push_compiledfunction(ctx);
12039 h_fun = duk_get_hcompiledfunction(ctx, -1);
12040 DUK_ASSERT(h_fun != NULL);
12041 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) h_fun));
12042 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, h_fun) == NULL);
12043 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_FUNCS(thr->heap, h_fun) == NULL);
12044 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_BYTECODE(thr->heap, h_fun) == NULL);
12045
12046 h_fun->nregs = DUK_RAW_READ_U16_BE(p);
12047 h_fun->nargs = DUK_RAW_READ_U16_BE(p);
12048#if defined(DUK_USE_DEBUGGER_SUPPORT)
12049 h_fun->start_line = DUK_RAW_READ_U32_BE(p);
12050 h_fun->end_line = DUK_RAW_READ_U32_BE(p);
12051#else
12052 p += 8; /* skip line info */
12053#endif
12054
12055 /* duk_hcompiledfunction flags; quite version specific */
12056 tmp32 = DUK_RAW_READ_U32_BE(p);
12057 DUK_HEAPHDR_SET_FLAGS((duk_heaphdr *) h_fun, tmp32);
12058
12059 /* standard prototype */
12060 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, &h_fun->obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
12061
12062 /* assert just a few critical flags */
12063 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h_fun) == DUK_HTYPE_OBJECT);
12064 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(&h_fun->obj));
12065 DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(&h_fun->obj));
12066 DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(&h_fun->obj));
12067 DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(&h_fun->obj));
12068 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(&h_fun->obj));
12069 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(&h_fun->obj));
12070 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(&h_fun->obj));
12071
12072 /* Create function 'data' buffer but don't attach it yet. */
12073 fun_data = (duk_uint8_t *) duk_push_fixed_buffer(ctx, data_size);
12074 DUK_ASSERT(fun_data != NULL);
12075
12076 /* Load bytecode instructions. */
12077 DUK_ASSERT(sizeof(duk_instr_t) == 4);
12078 DUK__ASSERT_LEFT(count_instr * sizeof(duk_instr_t));
12079#if defined(DUK_USE_INTEGER_BE)
12080 q = fun_data + sizeof(duk_tval) * count_const + sizeof(duk_hobject *) * count_funcs;
12081 DUK_MEMCPY((void *) q,
12082 (const void *) p,
12083 sizeof(duk_instr_t) * count_instr);
12084 p += sizeof(duk_instr_t) * count_instr;
12085#else
12086 q = fun_data + sizeof(duk_tval) * count_const + sizeof(duk_hobject *) * count_funcs;
12087 for (n = count_instr; n > 0; n--) {
12088 *((duk_instr_t *) (void *) q) = DUK_RAW_READ_U32_BE(p);
12089 q += sizeof(duk_instr_t);
12090 }
12091#endif
12092
12093 /* Load constants onto value stack but don't yet copy to buffer. */
12094 for (n = count_const; n > 0; n--) {
12095 DUK__ASSERT_LEFT(1);
12096 const_type = DUK_RAW_READ_U8(p);
12097 switch (const_type) {
12098 case DUK__SER_STRING: {
12099 p = duk__load_string_raw(ctx, p);
12100 break;
12101 }
12102 case DUK__SER_NUMBER: {
12103 /* Important to do a fastint check so that constants are
12104 * properly read back as fastints.
12105 */
12106 duk_tval tv_tmp;
12107 duk_double_t val;
12108 DUK__ASSERT_LEFT(8);
12109 val = DUK_RAW_READ_DOUBLE_BE(p);
12110 DUK_TVAL_SET_NUMBER_CHKFAST(&tv_tmp, val);
12111 duk_push_tval(ctx, &tv_tmp);
12112 break;
12113 }
12114 default: {
12115 goto format_error;
12116 }
12117 }
12118 }
12119
12120 /* Load inner functions to value stack, but don't yet copy to buffer. */
12121 for (n = count_funcs; n > 0; n--) {
12122 p = duk__load_func(ctx, p, p_end);
12123 if (p == NULL) {
12124 goto format_error;
12125 }
12126 }
12127
12128 /* With constants and inner functions on value stack, we can now
12129 * atomically finish the function 'data' buffer, bump refcounts,
12130 * etc.
12131 *
12132 * Here we take advantage of the value stack being just a duk_tval
12133 * array: we can just memcpy() the constants as long as we incref
12134 * them afterwards.
12135 */
12136
12137 h_data = (duk_hbuffer *) duk_get_hbuffer(ctx, idx_base + 1);
12138 DUK_ASSERT(h_data != NULL);
12139 DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC(h_data));
12140 DUK_HCOMPILEDFUNCTION_SET_DATA(thr->heap, h_fun, h_data);
12141 DUK_HBUFFER_INCREF(thr, h_data);
12142
12143 tv1 = duk_get_tval(ctx, idx_base + 2); /* may be NULL if no constants or inner funcs */
12144 DUK_ASSERT((count_const == 0 && count_funcs == 0) || tv1 != NULL);
12145
12146 q = fun_data;
12147 if (count_const > 0) {
12148 /* Explicit zero size check to avoid NULL 'tv1'. */
12149 DUK_MEMCPY((void *) q, (const void *) tv1, sizeof(duk_tval) * count_const);
12150 for (n = count_const; n > 0; n--) {
12151 DUK_TVAL_INCREF_FAST(thr, (duk_tval *) (void *) q); /* no side effects */
12152 q += sizeof(duk_tval);
12153 }
12154 tv1 += count_const;
12155 }
12156
12157 DUK_HCOMPILEDFUNCTION_SET_FUNCS(thr->heap, h_fun, (duk_hobject **) (void *) q);
12158 for (n = count_funcs; n > 0; n--) {
12159 duk_hobject *h_obj;
12160
12161 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1));
12162 h_obj = DUK_TVAL_GET_OBJECT(tv1);
12163 DUK_ASSERT(h_obj != NULL);
12164 tv1++;
12165 DUK_HOBJECT_INCREF(thr, h_obj);
12166
12167 *((duk_hobject **) (void *) q) = h_obj;
12168 q += sizeof(duk_hobject *);
12169 }
12170
12171 DUK_HCOMPILEDFUNCTION_SET_BYTECODE(thr->heap, h_fun, (duk_instr_t *) (void *) q);
12172
12173 /* The function object is now reachable and refcounts are fine,
12174 * so we can pop off all the temporaries.
12175 */
12176 DUK_DDD(DUK_DDDPRINT("function is reachable, reset top; func: %!iT", duk_get_tval(ctx, idx_base)));
12177 duk_set_top(ctx, idx_base + 1);
12178
12179 /* Setup function properties. */
12180 tmp32 = DUK_RAW_READ_U32_BE(p);
12181 duk_push_u32(ctx, tmp32);
12182 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
12183
12184 p = duk__load_string_raw(ctx, p);
12185 if (DUK_HOBJECT_HAS_NAMEBINDING((duk_hobject *) h_fun)) {
12186 /* Original function instance/template had NAMEBINDING.
12187 * Must create a lexical environment on loading to allow
12188 * recursive functions like 'function foo() { foo(); }'.
12189 */
12190 duk_hobject *proto;
12191
12192 proto = thr->builtins[DUK_BIDX_GLOBAL_ENV];
12193 (void) duk_push_object_helper_proto(ctx,
12194 DUK_HOBJECT_FLAG_EXTENSIBLE |
12195 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
12196 proto);
12197 duk_dup(ctx, -2); /* -> [ func funcname env funcname ] */
12198 duk_dup(ctx, idx_base); /* -> [ func funcname env funcname func ] */
12199 duk_xdef_prop(ctx, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ func funcname env ] */
12200 duk_xdef_prop_stridx(ctx, idx_base, DUK_STRIDX_INT_LEXENV, DUK_PROPDESC_FLAGS_WC);
12201 /* since closure has NEWENV, never define DUK_STRIDX_INT_VARENV, as it
12202 * will be ignored anyway
12203 */
12204 }
12205 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
12206
12207 p = duk__load_string_raw(ctx, p);
12208 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC);
12209
12210 duk_push_object(ctx);
12211 duk_dup(ctx, -2);
12212 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* func.prototype.constructor = func */
12213 duk_compact(ctx, -1);
12214 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W);
12215
12216 p = duk__load_buffer_raw(ctx, p);
12217 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_WC);
12218
12219 duk_push_object(ctx); /* _Varmap */
12220 for (;;) {
12221 /* XXX: awkward */
12222 p = duk__load_string_raw(ctx, p);
12223 if (duk_get_length(ctx, -1) == 0) {
12224 duk_pop(ctx);
12225 break;
12226 }
12227 tmp32 = DUK_RAW_READ_U32_BE(p);
12228 duk_push_u32(ctx, tmp32);
12229 duk_put_prop(ctx, -3);
12230 }
12231 duk_compact(ctx, -1);
12232 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE);
12233
12234 duk_push_array(ctx); /* _Formals */
12235 for (arr_idx = 0; ; arr_idx++) {
12236 /* XXX: awkward */
12237 p = duk__load_string_raw(ctx, p);
12238 if (duk_get_length(ctx, -1) == 0) {
12239 duk_pop(ctx);
12240 break;
12241 }
12242 duk_put_prop_index(ctx, -2, arr_idx);
12243 }
12244 duk_compact(ctx, -1);
12245 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE);
12246
12247 /* Return with final function pushed on stack top. */
12248 DUK_DD(DUK_DDPRINT("final loaded function: %!iT", duk_get_tval(ctx, -1)));
12249 DUK_ASSERT_TOP(ctx, idx_base + 1);
12250 return p;
12251
12252 format_error:
12253 return NULL;
12254}
12255
12256DUK_EXTERNAL void duk_dump_function(duk_context *ctx) {
12257 duk_hthread *thr;
12258 duk_hcompiledfunction *func;
12259 duk_bufwriter_ctx bw_ctx_alloc;
12260 duk_bufwriter_ctx *bw_ctx = &bw_ctx_alloc;
12261 duk_uint8_t *p;
12262
12263 DUK_ASSERT(ctx != NULL);
12264 thr = (duk_hthread *) ctx;
12265
12266 /* Bound functions don't have all properties so we'd either need to
12267 * lookup the non-bound target function or reject bound functions.
12268 * For now, bound functions are rejected.
12269 */
12270 func = duk_require_hcompiledfunction(ctx, -1);
12271 DUK_ASSERT(func != NULL);
12272 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(&func->obj));
12273
12274 /* Estimating the result size beforehand would be costly, so
12275 * start with a reasonable size and extend as needed.
12276 */
12277 DUK_BW_INIT_PUSHBUF(thr, bw_ctx, DUK__BYTECODE_INITIAL_ALLOC);
12278 p = DUK_BW_GET_PTR(thr, bw_ctx);
12279 *p++ = DUK__SER_MARKER;
12280 *p++ = DUK__SER_VERSION;
12281 p = duk__dump_func(ctx, func, bw_ctx, p);
12282 DUK_BW_SET_PTR(thr, bw_ctx, p);
12283 DUK_BW_COMPACT(thr, bw_ctx);
12284
12285 DUK_DD(DUK_DDPRINT("serialized result: %!T", duk_get_tval(ctx, -1)));
12286
12287 duk_remove(ctx, -2); /* [ ... func buf ] -> [ ... buf ] */
12288}
12289
12290DUK_EXTERNAL void duk_load_function(duk_context *ctx) {
12291 duk_hthread *thr;
12292 duk_uint8_t *p_buf, *p, *p_end;
12293 duk_size_t sz;
12294
12295 DUK_ASSERT(ctx != NULL);
12296 thr = (duk_hthread *) ctx;
12297 DUK_UNREF(ctx);
12298
12299 p_buf = (duk_uint8_t *) duk_require_buffer(ctx, -1, &sz);
12300 DUK_ASSERT(p_buf != NULL);
12301
12302 /* The caller is responsible for being sure that bytecode being loaded
12303 * is valid and trusted. Invalid bytecode can cause memory unsafe
12304 * behavior directly during loading or later during bytecode execution
12305 * (instruction validation would be quite complex to implement).
12306 *
12307 * This signature check is the only sanity check for detecting
12308 * accidental invalid inputs. The initial 0xFF byte ensures no
12309 * ordinary string will be accepted by accident.
12310 */
12311 p = p_buf;
12312 p_end = p_buf + sz;
12313 if (sz < 2 || p[0] != DUK__SER_MARKER || p[1] != DUK__SER_VERSION) {
12314 goto format_error;
12315 }
12316 p += 2;
12317
12318 p = duk__load_func(ctx, p, p_end);
12319 if (p == NULL) {
12320 goto format_error;
12321 }
12322
12323 duk_remove(ctx, -2); /* [ ... buf func ] -> [ ... func ] */
12324 return;
12325
12326 format_error:
11fdf7f2 12327 DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED);
7c673cae
FG
12328}
12329
12330#undef DUK__SER_MARKER
12331#undef DUK__SER_VERSION
12332#undef DUK__SER_STRING
12333#undef DUK__SER_NUMBER
12334#undef DUK__BYTECODE_INITIAL_ALLOC
12335
12336#else /* DUK_USE_BYTECODE_DUMP_SUPPORT */
12337
12338DUK_EXTERNAL void duk_dump_function(duk_context *ctx) {
11fdf7f2 12339 DUK_ERROR_UNSUPPORTED_DEFMSG((duk_hthread *) ctx);
7c673cae
FG
12340}
12341
12342DUK_EXTERNAL void duk_load_function(duk_context *ctx) {
11fdf7f2 12343 DUK_ERROR_UNSUPPORTED_DEFMSG((duk_hthread *) ctx);
7c673cae
FG
12344}
12345
12346#endif /* DUK_USE_BYTECODE_DUMP_SUPPORT */
7c673cae
FG
12347/*
12348 * Calls.
12349 *
12350 * Protected variants should avoid ever throwing an error.
12351 */
12352
12353/* include removed: duk_internal.h */
12354
12355/* Prepare value stack for a method call through an object property.
12356 * May currently throw an error e.g. when getting the property.
12357 */
12358DUK_LOCAL void duk__call_prop_prep_stack(duk_context *ctx, duk_idx_t normalized_obj_index, duk_idx_t nargs) {
12359 DUK_ASSERT_CTX_VALID(ctx);
12360
12361 DUK_DDD(DUK_DDDPRINT("duk__call_prop_prep_stack, normalized_obj_index=%ld, nargs=%ld, stacktop=%ld",
12362 (long) normalized_obj_index, (long) nargs, (long) duk_get_top(ctx)));
12363
12364 /* [... key arg1 ... argN] */
12365
12366 /* duplicate key */
12367 duk_dup(ctx, -nargs - 1); /* Note: -nargs alone would fail for nargs == 0, this is OK */
12368 duk_get_prop(ctx, normalized_obj_index);
12369
12370 DUK_DDD(DUK_DDDPRINT("func: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
12371
12372 /* [... key arg1 ... argN func] */
12373
12374 duk_replace(ctx, -nargs - 2);
12375
12376 /* [... func arg1 ... argN] */
12377
12378 duk_dup(ctx, normalized_obj_index);
12379 duk_insert(ctx, -nargs - 1);
12380
12381 /* [... func this arg1 ... argN] */
12382}
12383
12384DUK_EXTERNAL void duk_call(duk_context *ctx, duk_idx_t nargs) {
12385 duk_hthread *thr = (duk_hthread *) ctx;
12386 duk_small_uint_t call_flags;
12387 duk_idx_t idx_func;
7c673cae
FG
12388
12389 DUK_ASSERT_CTX_VALID(ctx);
12390 DUK_ASSERT(thr != NULL);
12391
12392 idx_func = duk_get_top(ctx) - nargs - 1;
12393 if (idx_func < 0 || nargs < 0) {
12394 /* note that we can't reliably pop anything here */
11fdf7f2 12395 DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
7c673cae
FG
12396 }
12397
12398 /* XXX: awkward; we assume there is space for this, overwrite
12399 * directly instead?
12400 */
12401 duk_push_undefined(ctx);
12402 duk_insert(ctx, idx_func + 1);
12403
12404 call_flags = 0; /* not protected, respect reclimit, not constructor */
12405
11fdf7f2
TL
12406 duk_handle_call_unprotected(thr, /* thread */
12407 nargs, /* num_stack_args */
12408 call_flags); /* call_flags */
7c673cae
FG
12409}
12410
12411DUK_EXTERNAL void duk_call_method(duk_context *ctx, duk_idx_t nargs) {
12412 duk_hthread *thr = (duk_hthread *) ctx;
12413 duk_small_uint_t call_flags;
12414 duk_idx_t idx_func;
7c673cae
FG
12415
12416 DUK_ASSERT_CTX_VALID(ctx);
12417 DUK_ASSERT(thr != NULL);
12418
12419 idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */
12420 if (idx_func < 0 || nargs < 0) {
12421 /* note that we can't reliably pop anything here */
11fdf7f2 12422 DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
7c673cae
FG
12423 }
12424
12425 call_flags = 0; /* not protected, respect reclimit, not constructor */
12426
11fdf7f2
TL
12427 duk_handle_call_unprotected(thr, /* thread */
12428 nargs, /* num_stack_args */
12429 call_flags); /* call_flags */
7c673cae
FG
12430}
12431
12432DUK_EXTERNAL void duk_call_prop(duk_context *ctx, duk_idx_t obj_index, duk_idx_t nargs) {
12433 /*
12434 * XXX: if duk_handle_call() took values through indices, this could be
12435 * made much more sensible. However, duk_handle_call() needs to fudge
12436 * the 'this' and 'func' values to handle bound function chains, which
12437 * is now done "in-place", so this is not a trivial change.
12438 */
12439
12440 DUK_ASSERT_CTX_VALID(ctx);
12441
12442 obj_index = duk_require_normalize_index(ctx, obj_index); /* make absolute */
11fdf7f2
TL
12443 if (DUK_UNLIKELY(nargs < 0)) {
12444 DUK_ERROR_API((duk_hthread *) ctx, DUK_STR_INVALID_CALL_ARGS);
12445 }
7c673cae
FG
12446
12447 duk__call_prop_prep_stack(ctx, obj_index, nargs);
12448
12449 duk_call_method(ctx, nargs);
12450}
12451
12452DUK_EXTERNAL duk_int_t duk_pcall(duk_context *ctx, duk_idx_t nargs) {
12453 duk_hthread *thr = (duk_hthread *) ctx;
12454 duk_small_uint_t call_flags;
12455 duk_idx_t idx_func;
12456 duk_int_t rc;
12457
12458 DUK_ASSERT_CTX_VALID(ctx);
12459 DUK_ASSERT(thr != NULL);
12460
12461 idx_func = duk_get_top(ctx) - nargs - 1; /* must work for nargs <= 0 */
12462 if (idx_func < 0 || nargs < 0) {
12463 /* We can't reliably pop anything here because the stack input
12464 * shape is incorrect. So we throw an error; if the caller has
12465 * no catch point for this, a fatal error will occur. Another
12466 * alternative would be to just return an error. But then the
12467 * stack would be in an unknown state which might cause some
12468 * very hard to diagnose problems later on. Also note that even
12469 * if we did not throw an error here, the underlying call handler
12470 * might STILL throw an out-of-memory error or some other internal
12471 * fatal error.
12472 */
11fdf7f2 12473 DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
7c673cae
FG
12474 return DUK_EXEC_ERROR; /* unreachable */
12475 }
12476
12477 /* awkward; we assume there is space for this */
12478 duk_push_undefined(ctx);
12479 duk_insert(ctx, idx_func + 1);
12480
11fdf7f2 12481 call_flags = 0; /* respect reclimit, not constructor */
7c673cae 12482
11fdf7f2
TL
12483 rc = duk_handle_call_protected(thr, /* thread */
12484 nargs, /* num_stack_args */
12485 call_flags); /* call_flags */
7c673cae
FG
12486
12487 return rc;
12488}
12489
12490DUK_EXTERNAL duk_int_t duk_pcall_method(duk_context *ctx, duk_idx_t nargs) {
12491 duk_hthread *thr = (duk_hthread *) ctx;
12492 duk_small_uint_t call_flags;
12493 duk_idx_t idx_func;
12494 duk_int_t rc;
12495
12496 DUK_ASSERT_CTX_VALID(ctx);
12497 DUK_ASSERT(thr != NULL);
12498
12499 idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */
12500 if (idx_func < 0 || nargs < 0) {
12501 /* See comments in duk_pcall(). */
11fdf7f2 12502 DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
7c673cae
FG
12503 return DUK_EXEC_ERROR; /* unreachable */
12504 }
12505
11fdf7f2 12506 call_flags = 0; /* respect reclimit, not constructor */
7c673cae 12507
11fdf7f2
TL
12508 rc = duk_handle_call_protected(thr, /* thread */
12509 nargs, /* num_stack_args */
12510 call_flags); /* call_flags */
7c673cae
FG
12511
12512 return rc;
12513}
12514
12515DUK_LOCAL duk_ret_t duk__pcall_prop_raw(duk_context *ctx) {
12516 duk_idx_t obj_index;
12517 duk_idx_t nargs;
12518
12519 /* Get the original arguments. Note that obj_index may be a relative
12520 * index so the stack must have the same top when we use it.
12521 */
12522
12523 DUK_ASSERT_CTX_VALID(ctx);
12524
12525 obj_index = (duk_idx_t) duk_get_int(ctx, -2);
12526 nargs = (duk_idx_t) duk_get_int(ctx, -1);
12527 duk_pop_2(ctx);
12528
12529 obj_index = duk_require_normalize_index(ctx, obj_index); /* make absolute */
12530 duk__call_prop_prep_stack(ctx, obj_index, nargs);
12531 duk_call_method(ctx, nargs);
12532 return 1;
12533}
12534
12535DUK_EXTERNAL duk_int_t duk_pcall_prop(duk_context *ctx, duk_idx_t obj_index, duk_idx_t nargs) {
12536 /*
12537 * Must be careful to catch errors related to value stack manipulation
12538 * and property lookup, not just the call itself.
12539 */
12540
12541 DUK_ASSERT_CTX_VALID(ctx);
12542
12543 duk_push_idx(ctx, obj_index);
11fdf7f2
TL
12544 if (DUK_UNLIKELY(nargs < 0)) {
12545 DUK_ERROR_API((duk_hthread *) ctx, DUK_STR_INVALID_CALL_ARGS);
12546 }
7c673cae
FG
12547 duk_push_idx(ctx, nargs);
12548
12549 /* Inputs: explicit arguments (nargs), +1 for key, +2 for obj_index/nargs passing.
12550 * If the value stack does not contain enough args, an error is thrown; this matches
12551 * behavior of the other protected call API functions.
12552 */
12553 return duk_safe_call(ctx, duk__pcall_prop_raw, nargs + 1 + 2 /*nargs*/, 1 /*nrets*/);
12554}
12555
12556DUK_EXTERNAL duk_int_t duk_safe_call(duk_context *ctx, duk_safe_call_function func, duk_idx_t nargs, duk_idx_t nrets) {
12557 duk_hthread *thr = (duk_hthread *) ctx;
12558 duk_int_t rc;
12559
12560 DUK_ASSERT_CTX_VALID(ctx);
12561 DUK_ASSERT(thr != NULL);
12562
11fdf7f2 12563 if (duk_get_top(ctx) < nargs || nargs < 0 || nrets < 0) {
7c673cae 12564 /* See comments in duk_pcall(). */
11fdf7f2 12565 DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
7c673cae
FG
12566 return DUK_EXEC_ERROR; /* unreachable */
12567 }
12568
12569 rc = duk_handle_safe_call(thr, /* thread */
12570 func, /* func */
12571 nargs, /* num_stack_args */
12572 nrets); /* num_stack_res */
12573
12574 return rc;
12575}
12576
12577DUK_EXTERNAL void duk_new(duk_context *ctx, duk_idx_t nargs) {
12578 /*
12579 * There are two [[Construct]] operations in the specification:
12580 *
12581 * - E5 Section 13.2.2: for Function objects
12582 * - E5 Section 15.3.4.5.2: for "bound" Function objects
12583 *
12584 * The chain of bound functions is resolved in Section 15.3.4.5.2,
12585 * with arguments "piling up" until the [[Construct]] internal
12586 * method is called on the final, actual Function object. Note
12587 * that the "prototype" property is looked up *only* from the
12588 * final object, *before* calling the constructor.
12589 *
12590 * Currently we follow the bound function chain here to get the
12591 * "prototype" property value from the final, non-bound function.
12592 * However, we let duk_handle_call() handle the argument "piling"
12593 * when the constructor is called. The bound function chain is
12594 * thus now processed twice.
12595 *
12596 * When constructing new Array instances, an unnecessary object is
12597 * created and discarded now: the standard [[Construct]] creates an
12598 * object, and calls the Array constructor. The Array constructor
12599 * returns an Array instance, which is used as the result value for
12600 * the "new" operation; the object created before the Array constructor
12601 * call is discarded.
12602 *
12603 * This would be easy to fix, e.g. by knowing that the Array constructor
12604 * will always create a replacement object and skip creating the fallback
12605 * object in that case.
12606 *
12607 * Note: functions called via "new" need to know they are called as a
12608 * constructor. For instance, built-in constructors behave differently
12609 * depending on how they are called.
12610 */
12611
12612 /* XXX: merge this with duk_js_call.c, as this function implements
12613 * core semantics (or perhaps merge the two files altogether).
12614 */
12615
12616 duk_hthread *thr = (duk_hthread *) ctx;
12617 duk_hobject *proto;
12618 duk_hobject *cons;
12619 duk_hobject *fallback;
12620 duk_idx_t idx_cons;
12621 duk_small_uint_t call_flags;
7c673cae
FG
12622
12623 DUK_ASSERT_CTX_VALID(ctx);
12624
12625 /* [... constructor arg1 ... argN] */
12626
12627 idx_cons = duk_require_normalize_index(ctx, -nargs - 1);
12628
12629 DUK_DDD(DUK_DDDPRINT("top=%ld, nargs=%ld, idx_cons=%ld",
12630 (long) duk_get_top(ctx), (long) nargs, (long) idx_cons));
12631
12632 /* XXX: code duplication */
12633
12634 /*
12635 * Figure out the final, non-bound constructor, to get "prototype"
12636 * property.
12637 */
12638
12639 duk_dup(ctx, idx_cons);
12640 for (;;) {
11fdf7f2
TL
12641 duk_tval *tv;
12642 tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
12643 DUK_ASSERT(tv != NULL);
12644
12645 if (DUK_TVAL_IS_OBJECT(tv)) {
12646 cons = DUK_TVAL_GET_OBJECT(tv);
12647 DUK_ASSERT(cons != NULL);
12648 if (!DUK_HOBJECT_IS_CALLABLE(cons) || !DUK_HOBJECT_HAS_CONSTRUCTABLE(cons)) {
12649 /* Checking callability of the immediate target
12650 * is important, same for constructability.
12651 * Checking it for functions down the bound
12652 * function chain is not strictly necessary
12653 * because .bind() should normally reject them.
12654 * But it's good to check anyway because it's
12655 * technically possible to edit the bound function
12656 * chain via internal keys.
12657 */
12658 goto not_constructable;
12659 }
12660 if (!DUK_HOBJECT_HAS_BOUND(cons)) {
12661 break;
12662 }
12663 } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
12664 /* Lightfuncs cannot be bound. */
7c673cae 12665 break;
11fdf7f2
TL
12666 } else {
12667 /* Anything else is not constructable. */
12668 goto not_constructable;
7c673cae
FG
12669 }
12670 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TARGET); /* -> [... cons target] */
12671 duk_remove(ctx, -2); /* -> [... target] */
12672 }
11fdf7f2
TL
12673 DUK_ASSERT(duk_is_callable(ctx, -1));
12674 DUK_ASSERT(duk_is_lightfunc(ctx, -1) ||
12675 (duk_get_hobject(ctx, -1) != NULL && !DUK_HOBJECT_HAS_BOUND(duk_get_hobject(ctx, -1))));
7c673cae
FG
12676
12677 /* [... constructor arg1 ... argN final_cons] */
12678
12679 /*
12680 * Create "fallback" object to be used as the object instance,
12681 * unless the constructor returns a replacement value.
12682 * Its internal prototype needs to be set based on "prototype"
12683 * property of the constructor.
12684 */
12685
12686 duk_push_object(ctx); /* class Object, extensible */
12687
12688 /* [... constructor arg1 ... argN final_cons fallback] */
12689
12690 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_PROTOTYPE);
12691 proto = duk_get_hobject(ctx, -1);
12692 if (!proto) {
12693 DUK_DDD(DUK_DDDPRINT("constructor has no 'prototype' property, or value not an object "
12694 "-> leave standard Object prototype as fallback prototype"));
12695 } else {
12696 DUK_DDD(DUK_DDDPRINT("constructor has 'prototype' property with object value "
12697 "-> set fallback prototype to that value: %!iO", (duk_heaphdr *) proto));
12698 fallback = duk_get_hobject(ctx, -2);
12699 DUK_ASSERT(fallback != NULL);
12700 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, fallback, proto);
12701 }
12702 duk_pop(ctx);
12703
12704 /* [... constructor arg1 ... argN final_cons fallback] */
12705
12706 /*
12707 * Manipulate callstack for the call.
12708 */
12709
12710 duk_dup_top(ctx);
12711 duk_insert(ctx, idx_cons + 1); /* use fallback as 'this' value */
12712 duk_insert(ctx, idx_cons); /* also stash it before constructor,
12713 * in case we need it (as the fallback value)
12714 */
12715 duk_pop(ctx); /* pop final_cons */
12716
12717
12718 /* [... fallback constructor fallback(this) arg1 ... argN];
12719 * Note: idx_cons points to first 'fallback', not 'constructor'.
12720 */
12721
12722 DUK_DDD(DUK_DDDPRINT("before call, idx_cons+1 (constructor) -> %!T, idx_cons+2 (fallback/this) -> %!T, "
12723 "nargs=%ld, top=%ld",
12724 (duk_tval *) duk_get_tval(ctx, idx_cons + 1),
12725 (duk_tval *) duk_get_tval(ctx, idx_cons + 2),
12726 (long) nargs,
12727 (long) duk_get_top(ctx)));
12728
12729 /*
12730 * Call the constructor function (called in "constructor mode").
12731 */
12732
12733 call_flags = DUK_CALL_FLAG_CONSTRUCTOR_CALL; /* not protected, respect reclimit, is a constructor call */
12734
11fdf7f2
TL
12735 duk_handle_call_unprotected(thr, /* thread */
12736 nargs, /* num_stack_args */
12737 call_flags); /* call_flags */
7c673cae
FG
12738
12739 /* [... fallback retval] */
12740
11fdf7f2 12741 DUK_DDD(DUK_DDDPRINT("constructor call finished, fallback=%!iT, retval=%!iT",
7c673cae
FG
12742 (duk_tval *) duk_get_tval(ctx, -2),
12743 (duk_tval *) duk_get_tval(ctx, -1)));
12744
12745 /*
12746 * Determine whether to use the constructor return value as the created
12747 * object instance or not.
12748 */
12749
12750 if (duk_is_object(ctx, -1)) {
12751 duk_remove(ctx, -2);
12752 } else {
12753 duk_pop(ctx);
12754 }
12755
12756 /*
12757 * Augment created errors upon creation (not when they are thrown or
12758 * rethrown). __FILE__ and __LINE__ are not desirable here; the call
12759 * stack reflects the caller which is correct.
12760 */
12761
12762#ifdef DUK_USE_AUGMENT_ERROR_CREATE
12763 duk_hthread_sync_currpc(thr);
12764 duk_err_augment_error_create(thr, thr, NULL, 0, 1 /*noblame_fileline*/);
12765#endif
12766
12767 /* [... retval] */
12768
12769 return;
12770
12771 not_constructable:
11fdf7f2 12772 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONSTRUCTABLE);
7c673cae
FG
12773}
12774
12775DUK_LOCAL duk_ret_t duk__pnew_helper(duk_context *ctx) {
12776 duk_uint_t nargs;
12777
12778 nargs = duk_to_uint(ctx, -1);
12779 duk_pop(ctx);
12780
12781 duk_new(ctx, nargs);
12782 return 1;
12783}
12784
12785DUK_EXTERNAL duk_int_t duk_pnew(duk_context *ctx, duk_idx_t nargs) {
12786 duk_int_t rc;
12787
12788 DUK_ASSERT_CTX_VALID(ctx);
12789
12790 /* For now, just use duk_safe_call() to wrap duk_new(). We can't
12791 * simply use a protected duk_handle_call() because there's post
12792 * processing which might throw. It should be possible to ensure
12793 * the post processing never throws (except in internal errors and
12794 * out of memory etc which are always allowed) and then remove this
12795 * wrapper.
12796 */
12797
11fdf7f2
TL
12798 if (DUK_UNLIKELY(nargs < 0)) {
12799 DUK_ERROR_API((duk_hthread *) ctx, DUK_STR_INVALID_CALL_ARGS);
12800 }
7c673cae
FG
12801 duk_push_uint(ctx, nargs);
12802 rc = duk_safe_call(ctx, duk__pnew_helper, nargs + 2 /*nargs*/, 1 /*nrets*/);
12803 return rc;
12804}
12805
12806DUK_EXTERNAL duk_bool_t duk_is_constructor_call(duk_context *ctx) {
12807 duk_hthread *thr = (duk_hthread *) ctx;
12808 duk_activation *act;
12809
12810 DUK_ASSERT_CTX_VALID(ctx);
12811 DUK_ASSERT(thr != NULL);
12812 DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
12813
12814 act = duk_hthread_get_current_activation(thr);
11fdf7f2
TL
12815 if (act != NULL) {
12816 return ((act->flags & DUK_ACT_FLAG_CONSTRUCT) != 0 ? 1 : 0);
12817 }
12818 return 0;
7c673cae
FG
12819}
12820
12821DUK_EXTERNAL duk_bool_t duk_is_strict_call(duk_context *ctx) {
12822 duk_hthread *thr = (duk_hthread *) ctx;
12823 duk_activation *act;
12824
12825 /* For user code this could just return 1 (strict) always
12826 * because all Duktape/C functions are considered strict,
12827 * and strict is also the default when nothing is running.
12828 * However, Duktape may call this function internally when
12829 * the current activation is an Ecmascript function, so
12830 * this cannot be replaced by a 'return 1' without fixing
12831 * the internal call sites.
12832 */
12833
12834 DUK_ASSERT_CTX_VALID(ctx);
12835 DUK_ASSERT(thr != NULL);
12836 DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
12837
12838 act = duk_hthread_get_current_activation(thr);
12839 if (act == NULL) {
12840 /* Strict by default. */
12841 return 1;
12842 }
12843 return ((act->flags & DUK_ACT_FLAG_STRICT) != 0 ? 1 : 0);
12844}
12845
12846/*
12847 * Duktape/C function magic
12848 */
12849
12850DUK_EXTERNAL duk_int_t duk_get_current_magic(duk_context *ctx) {
12851 duk_hthread *thr = (duk_hthread *) ctx;
12852 duk_activation *act;
12853 duk_hobject *func;
12854
12855 DUK_ASSERT_CTX_VALID(ctx);
12856 DUK_ASSERT(thr != NULL);
12857 DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
12858
12859 act = duk_hthread_get_current_activation(thr);
12860 if (act) {
12861 func = DUK_ACT_GET_FUNC(act);
12862 if (!func) {
12863 duk_tval *tv = &act->tv_func;
12864 duk_small_uint_t lf_flags;
12865 lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
12866 return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags);
12867 }
12868 DUK_ASSERT(func != NULL);
12869
12870 if (DUK_HOBJECT_IS_NATIVEFUNCTION(func)) {
12871 duk_hnativefunction *nf = (duk_hnativefunction *) func;
12872 return (duk_int_t) nf->magic;
12873 }
12874 }
12875 return 0;
12876}
12877
12878DUK_EXTERNAL duk_int_t duk_get_magic(duk_context *ctx, duk_idx_t index) {
12879 duk_hthread *thr = (duk_hthread *) ctx;
12880 duk_tval *tv;
12881 duk_hobject *h;
12882
12883 DUK_ASSERT_CTX_VALID(ctx);
12884
12885 tv = duk_require_tval(ctx, index);
12886 if (DUK_TVAL_IS_OBJECT(tv)) {
12887 h = DUK_TVAL_GET_OBJECT(tv);
12888 DUK_ASSERT(h != NULL);
12889 if (!DUK_HOBJECT_HAS_NATIVEFUNCTION(h)) {
12890 goto type_error;
12891 }
12892 return (duk_int_t) ((duk_hnativefunction *) h)->magic;
12893 } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
12894 duk_small_uint_t lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
12895 return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags);
12896 }
12897
12898 /* fall through */
12899 type_error:
11fdf7f2 12900 DUK_ERROR_TYPE(thr, DUK_STR_UNEXPECTED_TYPE);
7c673cae
FG
12901 return 0;
12902}
12903
12904DUK_EXTERNAL void duk_set_magic(duk_context *ctx, duk_idx_t index, duk_int_t magic) {
12905 duk_hnativefunction *nf;
12906
12907 DUK_ASSERT_CTX_VALID(ctx);
12908
12909 nf = duk_require_hnativefunction(ctx, index);
12910 DUK_ASSERT(nf != NULL);
12911 nf->magic = (duk_int16_t) magic;
12912}
7c673cae
FG
12913/*
12914 * Encoding and decoding basic formats: hex, base64.
12915 *
12916 * These are in-place operations which may allow an optimized implementation.
11fdf7f2
TL
12917 *
12918 * Base-64: https://tools.ietf.org/html/rfc4648#section-4
7c673cae
FG
12919 */
12920
12921/* include removed: duk_internal.h */
12922
11fdf7f2
TL
12923/* Shared handling for encode/decode argument. Fast path handling for
12924 * buffer and string values because they're the most common. In particular,
12925 * avoid creating a temporary string or buffer when possible.
12926 */
12927DUK_LOCAL const duk_uint8_t *duk__prep_codec_arg(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) {
12928 DUK_ASSERT(duk_is_valid_index(ctx, index)); /* checked by caller */
12929 if (duk_is_buffer(ctx, index)) {
12930 return (const duk_uint8_t *) duk_get_buffer(ctx, index, out_len);
12931 } else {
12932 return (const duk_uint8_t *) duk_to_lstring(ctx, index, out_len);
12933 }
12934}
12935
12936#if defined(DUK_USE_BASE64_FASTPATH)
12937DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) {
12938 duk_uint_t t;
12939 duk_size_t n_full, n_full3, n_final;
12940 const duk_uint8_t *src_end_fast;
12941
12942 n_full = srclen / 3; /* full 3-byte -> 4-char conversions */
12943 n_full3 = n_full * 3;
12944 n_final = srclen - n_full3;
12945 DUK_ASSERT_DISABLE(n_final >= 0);
12946 DUK_ASSERT(n_final <= 2);
12947
12948 src_end_fast = src + n_full3;
12949 while (DUK_UNLIKELY(src != src_end_fast)) {
12950 t = (duk_uint_t) (*src++);
12951 t = (t << 8) + (duk_uint_t) (*src++);
12952 t = (t << 8) + (duk_uint_t) (*src++);
12953
12954 *dst++ = duk_base64_enctab[t >> 18];
12955 *dst++ = duk_base64_enctab[(t >> 12) & 0x3f];
12956 *dst++ = duk_base64_enctab[(t >> 6) & 0x3f];
12957 *dst++ = duk_base64_enctab[t & 0x3f];
12958
12959#if 0 /* Tested: not faster on x64 */
12960 /* aaaaaabb bbbbcccc ccdddddd */
12961 dst[0] = duk_base64_enctab[(src[0] >> 2) & 0x3f];
12962 dst[1] = duk_base64_enctab[((src[0] << 4) & 0x30) | ((src[1] >> 4) & 0x0f)];
12963 dst[2] = duk_base64_enctab[((src[1] << 2) & 0x3f) | ((src[2] >> 6) & 0x03)];
12964 dst[3] = duk_base64_enctab[src[2] & 0x3f];
12965 src += 3; dst += 4;
12966#endif
12967 }
12968
12969 switch (n_final) {
12970 /* case 0: nop */
12971 case 1: {
12972 /* XX== */
12973 t = (duk_uint_t) (*src++);
12974 *dst++ = duk_base64_enctab[t >> 2]; /* XXXXXX-- */
12975 *dst++ = duk_base64_enctab[(t << 4) & 0x3f]; /* ------XX */
12976 *dst++ = DUK_ASC_EQUALS;
12977 *dst++ = DUK_ASC_EQUALS;
12978 break;
12979 }
12980 case 2: {
12981 /* XXX= */
12982 t = (duk_uint_t) (*src++);
12983 t = (t << 8) + (duk_uint_t) (*src++);
12984 *dst++ = duk_base64_enctab[t >> 10]; /* XXXXXX-- -------- */
12985 *dst++ = duk_base64_enctab[(t >> 4) & 0x3f]; /* ------XX XXXX---- */
12986 *dst++ = duk_base64_enctab[(t << 2) & 0x3f]; /* -------- ----XXXX */
12987 *dst++ = DUK_ASC_EQUALS;
12988 break;
12989 }
12990 }
12991}
12992#else /* DUK_USE_BASE64_FASTPATH */
12993DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) {
7c673cae 12994 duk_small_uint_t i, snip;
11fdf7f2 12995 duk_uint_t t;
7c673cae 12996 duk_uint_fast8_t x, y;
11fdf7f2 12997 const duk_uint8_t *src_end;
7c673cae 12998
11fdf7f2 12999 src_end = src + srclen;
7c673cae
FG
13000
13001 while (src < src_end) {
13002 /* read 3 bytes into 't', padded by zero */
13003 snip = 4;
13004 t = 0;
13005 for (i = 0; i < 3; i++) {
13006 t = t << 8;
13007 if (src >= src_end) {
13008 snip--;
13009 } else {
11fdf7f2 13010 t += (duk_uint_t) (*src++);
7c673cae
FG
13011 }
13012 }
13013
13014 /*
13015 * Missing bytes snip base64 example
13016 * 0 4 XXXX
13017 * 1 3 XXX=
13018 * 2 2 XX==
13019 */
13020
13021 DUK_ASSERT(snip >= 2 && snip <= 4);
13022
13023 for (i = 0; i < 4; i++) {
13024 x = (duk_uint_fast8_t) ((t >> 18) & 0x3f);
13025 t = t << 6;
13026
13027 /* A straightforward 64-byte lookup would be faster
13028 * and cleaner, but this is shorter.
13029 */
13030 if (i >= snip) {
13031 y = '=';
13032 } else if (x <= 25) {
13033 y = x + 'A';
13034 } else if (x <= 51) {
13035 y = x - 26 + 'a';
13036 } else if (x <= 61) {
13037 y = x - 52 + '0';
13038 } else if (x == 62) {
13039 y = '+';
13040 } else {
13041 y = '/';
13042 }
13043
7c673cae
FG
13044 *dst++ = (duk_uint8_t) y;
13045 }
13046 }
13047}
11fdf7f2
TL
13048#endif /* DUK_USE_BASE64_FASTPATH */
13049
13050#if defined(DUK_USE_BASE64_FASTPATH)
13051DUK_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) {
13052 duk_int_t x;
13053 duk_int_t t;
13054 duk_small_uint_t n_equal;
13055 duk_small_uint_t n_chars;
13056 const duk_uint8_t *src_end;
13057 const duk_uint8_t *src_end_safe;
7c673cae 13058
11fdf7f2
TL
13059 src_end = src + srclen;
13060 src_end_safe = src_end - 4; /* if 'src < src_end_safe', safe to read 4 bytes */
13061
13062 /* Innermost fast path processes 4 valid base-64 characters at a time
13063 * but bails out on whitespace, padding chars ('=') and invalid chars.
13064 * Once the slow path segment has been processed, we return to the
13065 * inner fast path again. This handles e.g. base64 with newlines
13066 * reasonably well because the majority of a line is in the fast path.
13067 */
13068 for (;;) {
13069 /* Fast path, handle units with just actual encoding characters. */
13070
13071 while (src <= src_end_safe) {
13072 /* The lookup byte is intentionally sign extended to (at least)
13073 * 32 bits and then ORed. This ensures that is at least 1 byte
13074 * is negative, the highest bit of 't' will be set at the end
13075 * and we don't need to check every byte.
13076 */
13077 DUK_DDD(DUK_DDDPRINT("fast loop: src=%p, src_end_safe=%p, src_end=%p",
13078 (const void *) src, (const void *) src_end_safe, (const void *) src_end));
13079
13080 t = (duk_int_t) duk_base64_dectab[*src++];
13081 t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++];
13082 t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++];
13083 t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++];
13084
13085 if (DUK_UNLIKELY(t < 0)) {
13086 DUK_DDD(DUK_DDDPRINT("fast loop unit was not clean, process one slow path unit"));
13087 src -= 4;
13088 break;
13089 }
13090
13091 DUK_ASSERT(t <= 0xffffffL);
13092 DUK_ASSERT((t >> 24) == 0);
13093 *dst++ = (duk_uint8_t) (t >> 16);
13094 *dst++ = (duk_uint8_t) ((t >> 8) & 0xff);
13095 *dst++ = (duk_uint8_t) (t & 0xff);
13096 }
13097
13098 /* Handle one slow path unit (or finish if we're done). */
13099
13100 n_equal = 0;
13101 n_chars = 0;
13102 t = 0;
13103 for (;;) {
13104 DUK_DDD(DUK_DDDPRINT("slow loop: src=%p, src_end=%p, n_chars=%ld, n_equal=%ld, t=%ld",
13105 (const void *) src, (const void *) src_end, (long) n_chars, (long) n_equal, (long) t));
13106
13107 if (DUK_UNLIKELY(src >= src_end)) {
13108 goto done; /* two level break */
13109 }
13110
13111 x = duk_base64_dectab[*src++];
13112 if (DUK_UNLIKELY(x < 0)) {
13113 if (x == -2) {
13114 continue; /* allowed ascii whitespace */
13115 } else if (x == -3) {
13116 n_equal++;
13117 t <<= 6;
13118 } else {
13119 DUK_ASSERT(x == -1);
13120 goto error;
13121 }
13122 } else {
13123 DUK_ASSERT(x >= 0 && x <= 63);
13124 if (n_equal > 0) {
13125 /* Don't allow actual chars after equal sign. */
13126 goto error;
13127 }
13128 t = (t << 6) + x;
13129 }
13130
13131 if (DUK_UNLIKELY(n_chars == 3)) {
13132 /* Emit 3 bytes and backtrack if there was padding. There's
13133 * always space for the whole 3 bytes so no check needed.
13134 */
13135 DUK_ASSERT(t <= 0xffffffL);
13136 DUK_ASSERT((t >> 24) == 0);
13137 *dst++ = (duk_uint8_t) (t >> 16);
13138 *dst++ = (duk_uint8_t) ((t >> 8) & 0xff);
13139 *dst++ = (duk_uint8_t) (t & 0xff);
13140
13141 if (DUK_UNLIKELY(n_equal > 0)) {
13142 DUK_ASSERT(n_equal <= 4);
13143
13144 /* There may be whitespace between the equal signs. */
13145 if (n_equal == 1) {
13146 /* XXX= */
13147 dst -= 1;
13148 } else if (n_equal == 2) {
13149 /* XX== */
13150 dst -= 2;
13151 } else {
13152 goto error; /* invalid padding */
13153 }
13154
13155 /* Continue parsing after padding, allows concatenated,
13156 * padded base64.
13157 */
13158 }
13159 break; /* back to fast loop */
13160 } else {
13161 n_chars++;
13162 }
13163 }
13164 }
13165 done:
13166 DUK_DDD(DUK_DDDPRINT("done; src=%p, src_end=%p, n_chars=%ld",
13167 (const void *) src, (const void *) src_end, (long) n_chars));
13168
13169 DUK_ASSERT(src == src_end);
13170
13171 if (n_chars != 0) {
13172 /* Here we'd have the option of decoding unpadded base64
13173 * (e.g. "xxxxyy" instead of "xxxxyy==". Currently not
13174 * accepted.
13175 */
13176 goto error;
13177 }
13178
13179 *out_dst_final = dst;
13180 return 1;
13181
13182 error:
13183 return 0;
13184}
13185#else /* DUK_USE_BASE64_FASTPATH */
13186DUK_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) {
13187 duk_uint_t t;
7c673cae
FG
13188 duk_uint_fast8_t x, y;
13189 duk_small_uint_t group_idx;
11fdf7f2
TL
13190 duk_small_uint_t n_equal;
13191 const duk_uint8_t *src_end;
7c673cae 13192
11fdf7f2 13193 src_end = src + srclen;
7c673cae
FG
13194 t = 0;
13195 group_idx = 0;
11fdf7f2 13196 n_equal = 0;
7c673cae
FG
13197
13198 while (src < src_end) {
13199 x = *src++;
13200
13201 if (x >= 'A' && x <= 'Z') {
13202 y = x - 'A' + 0;
13203 } else if (x >= 'a' && x <= 'z') {
13204 y = x - 'a' + 26;
13205 } else if (x >= '0' && x <= '9') {
13206 y = x - '0' + 52;
13207 } else if (x == '+') {
13208 y = 62;
13209 } else if (x == '/') {
13210 y = 63;
13211 } else if (x == '=') {
11fdf7f2
TL
13212 /* We don't check the zero padding bytes here right now
13213 * (that they're actually zero). This seems to be common
13214 * behavior for base-64 decoders.
7c673cae
FG
13215 */
13216
11fdf7f2
TL
13217 n_equal++;
13218 t <<= 6; /* shift in zeroes */
13219 goto skip_add;
7c673cae
FG
13220 } else if (x == 0x09 || x == 0x0a || x == 0x0d || x == 0x20) {
13221 /* allow basic ASCII whitespace */
13222 continue;
13223 } else {
13224 goto error;
13225 }
13226
11fdf7f2
TL
13227 if (n_equal > 0) {
13228 /* Don't allow mixed padding and actual chars. */
13229 goto error;
13230 }
7c673cae 13231 t = (t << 6) + y;
11fdf7f2 13232 skip_add:
7c673cae
FG
13233
13234 if (group_idx == 3) {
13235 /* output 3 bytes from 't' */
7c673cae 13236 *dst++ = (duk_uint8_t) ((t >> 16) & 0xff);
7c673cae 13237 *dst++ = (duk_uint8_t) ((t >> 8) & 0xff);
7c673cae 13238 *dst++ = (duk_uint8_t) (t & 0xff);
11fdf7f2
TL
13239
13240 if (DUK_UNLIKELY(n_equal > 0)) {
13241 /* Backtrack. */
13242 DUK_ASSERT(n_equal <= 4);
13243 if (n_equal == 1) {
13244 dst -= 1;
13245 } else if (n_equal == 2) {
13246 dst -= 2;
13247 } else {
13248 goto error; /* invalid padding */
13249 }
13250
13251 /* Here we can choose either to end parsing and ignore
13252 * whatever follows, or to continue parsing in case
13253 * multiple (possibly padded) base64 strings have been
13254 * concatenated. Currently, keep on parsing.
13255 */
13256 n_equal = 0;
13257 }
13258
7c673cae
FG
13259 t = 0;
13260 group_idx = 0;
13261 } else {
13262 group_idx++;
13263 }
13264 }
13265
13266 if (group_idx != 0) {
13267 /* Here we'd have the option of decoding unpadded base64
13268 * (e.g. "xxxxyy" instead of "xxxxyy==". Currently not
13269 * accepted.
13270 */
13271 goto error;
13272 }
13273
13274 *out_dst_final = dst;
13275 return 1;
13276
13277 error:
13278 return 0;
13279}
11fdf7f2 13280#endif /* DUK_USE_BASE64_FASTPATH */
7c673cae
FG
13281
13282DUK_EXTERNAL const char *duk_base64_encode(duk_context *ctx, duk_idx_t index) {
13283 duk_hthread *thr = (duk_hthread *) ctx;
11fdf7f2 13284 const duk_uint8_t *src;
7c673cae
FG
13285 duk_size_t srclen;
13286 duk_size_t dstlen;
13287 duk_uint8_t *dst;
13288 const char *ret;
13289
13290 DUK_ASSERT_CTX_VALID(ctx);
13291
13292 /* XXX: optimize for string inputs: no need to coerce to a buffer
13293 * which makes a copy of the input.
13294 */
13295
13296 index = duk_require_normalize_index(ctx, index);
11fdf7f2 13297 src = duk__prep_codec_arg(ctx, index, &srclen);
7c673cae
FG
13298 /* Note: for srclen=0, src may be NULL */
13299
13300 /* Computation must not wrap; this limit works for 32-bit size_t:
13301 * >>> srclen = 3221225469
13302 * >>> '%x' % ((srclen + 2) / 3 * 4)
13303 * 'fffffffc'
13304 */
13305 if (srclen > 3221225469UL) {
13306 goto type_error;
13307 }
13308 dstlen = (srclen + 2) / 3 * 4;
13309 dst = (duk_uint8_t *) duk_push_fixed_buffer(ctx, dstlen);
13310
11fdf7f2 13311 duk__base64_encode_helper((const duk_uint8_t *) src, srclen, dst);
7c673cae
FG
13312
13313 ret = duk_to_string(ctx, -1);
13314 duk_replace(ctx, index);
13315 return ret;
13316
13317 type_error:
11fdf7f2 13318 DUK_ERROR_TYPE(thr, DUK_STR_ENCODE_FAILED);
7c673cae
FG
13319 return NULL; /* never here */
13320}
13321
13322DUK_EXTERNAL void duk_base64_decode(duk_context *ctx, duk_idx_t index) {
13323 duk_hthread *thr = (duk_hthread *) ctx;
13324 const duk_uint8_t *src;
13325 duk_size_t srclen;
13326 duk_size_t dstlen;
13327 duk_uint8_t *dst;
13328 duk_uint8_t *dst_final;
13329 duk_bool_t retval;
13330
13331 DUK_ASSERT_CTX_VALID(ctx);
13332
13333 /* XXX: optimize for buffer inputs: no need to coerce to a string
13334 * which causes an unnecessary interning.
13335 */
13336
13337 index = duk_require_normalize_index(ctx, index);
11fdf7f2 13338 src = duk__prep_codec_arg(ctx, index, &srclen);
7c673cae
FG
13339
13340 /* Computation must not wrap, only srclen + 3 is at risk of
13341 * wrapping because after that the number gets smaller.
13342 * This limit works for 32-bit size_t:
13343 * 0x100000000 - 3 - 1 = 4294967292
13344 */
13345 if (srclen > 4294967292UL) {
13346 goto type_error;
13347 }
11fdf7f2 13348 dstlen = (srclen + 3) / 4 * 3; /* upper limit, assuming no whitespace etc */
7c673cae
FG
13349 dst = (duk_uint8_t *) duk_push_dynamic_buffer(ctx, dstlen);
13350 /* Note: for dstlen=0, dst may be NULL */
13351
11fdf7f2 13352 retval = duk__base64_decode_helper((const duk_uint8_t *) src, srclen, dst, &dst_final);
7c673cae
FG
13353 if (!retval) {
13354 goto type_error;
13355 }
13356
13357 /* XXX: convert to fixed buffer? */
13358 (void) duk_resize_buffer(ctx, -1, (duk_size_t) (dst_final - dst));
13359 duk_replace(ctx, index);
13360 return;
13361
13362 type_error:
11fdf7f2 13363 DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED);
7c673cae
FG
13364}
13365
13366DUK_EXTERNAL const char *duk_hex_encode(duk_context *ctx, duk_idx_t index) {
13367 const duk_uint8_t *inp;
13368 duk_size_t len;
13369 duk_size_t i;
7c673cae
FG
13370 duk_uint8_t *buf;
13371 const char *ret;
11fdf7f2
TL
13372#if defined(DUK_USE_HEX_FASTPATH)
13373 duk_size_t len_safe;
13374 duk_uint16_t *p16;
13375#endif
7c673cae
FG
13376
13377 DUK_ASSERT_CTX_VALID(ctx);
13378
13379 index = duk_require_normalize_index(ctx, index);
13380 inp = duk__prep_codec_arg(ctx, index, &len);
13381 DUK_ASSERT(inp != NULL || len == 0);
13382
13383 /* Fixed buffer, no zeroing because we'll fill all the data. */
13384 buf = (duk_uint8_t *) duk_push_buffer_raw(ctx, len * 2, DUK_BUF_FLAG_NOZERO /*flags*/);
13385 DUK_ASSERT(buf != NULL);
13386
11fdf7f2
TL
13387#if defined(DUK_USE_HEX_FASTPATH)
13388 DUK_ASSERT((((duk_size_t) buf) & 0x01U) == 0); /* pointer is aligned, guaranteed for fixed buffer */
13389 p16 = (duk_uint16_t *) (void *) buf;
13390 len_safe = len & ~0x03U;
13391 for (i = 0; i < len_safe; i += 4) {
13392 p16[0] = duk_hex_enctab[inp[i]];
13393 p16[1] = duk_hex_enctab[inp[i + 1]];
13394 p16[2] = duk_hex_enctab[inp[i + 2]];
13395 p16[3] = duk_hex_enctab[inp[i + 3]];
13396 p16 += 4;
13397 }
13398 for (; i < len; i++) {
13399 *p16++ = duk_hex_enctab[inp[i]];
13400 }
13401#else /* DUK_USE_HEX_FASTPATH */
7c673cae 13402 for (i = 0; i < len; i++) {
11fdf7f2 13403 duk_small_uint_t t;
7c673cae
FG
13404 t = (duk_small_uint_t) inp[i];
13405 buf[i*2 + 0] = duk_lc_digits[t >> 4];
13406 buf[i*2 + 1] = duk_lc_digits[t & 0x0f];
13407 }
11fdf7f2 13408#endif /* DUK_USE_HEX_FASTPATH */
7c673cae
FG
13409
13410 /* XXX: Using a string return value forces a string intern which is
13411 * not always necessary. As a rough performance measure, hex encode
13412 * time for tests/perf/test-hex-encode.js dropped from ~35s to ~15s
13413 * without string coercion. Change to returning a buffer and let the
13414 * caller coerce to string if necessary?
13415 */
13416
13417 ret = duk_to_string(ctx, -1);
13418 duk_replace(ctx, index);
13419 return ret;
13420}
13421
13422DUK_EXTERNAL void duk_hex_decode(duk_context *ctx, duk_idx_t index) {
13423 duk_hthread *thr = (duk_hthread *) ctx;
13424 const duk_uint8_t *inp;
13425 duk_size_t len;
13426 duk_size_t i;
11fdf7f2 13427 duk_int_t t;
7c673cae 13428 duk_uint8_t *buf;
11fdf7f2
TL
13429#if defined(DUK_USE_HEX_FASTPATH)
13430 duk_int_t chk;
13431 duk_uint8_t *p;
13432 duk_size_t len_safe;
13433#endif
7c673cae
FG
13434
13435 DUK_ASSERT_CTX_VALID(ctx);
13436
13437 index = duk_require_normalize_index(ctx, index);
13438 inp = duk__prep_codec_arg(ctx, index, &len);
13439 DUK_ASSERT(inp != NULL || len == 0);
13440
13441 if (len & 0x01) {
13442 goto type_error;
13443 }
13444
13445 /* Fixed buffer, no zeroing because we'll fill all the data. */
13446 buf = (duk_uint8_t *) duk_push_buffer_raw(ctx, len / 2, DUK_BUF_FLAG_NOZERO /*flags*/);
13447 DUK_ASSERT(buf != NULL);
13448
11fdf7f2
TL
13449#if defined(DUK_USE_HEX_FASTPATH)
13450 p = buf;
13451 len_safe = len & ~0x07U;
13452 for (i = 0; i < len_safe; i += 8) {
13453 t = ((duk_int_t) duk_hex_dectab_shift4[inp[i]]) |
13454 ((duk_int_t) duk_hex_dectab[inp[i + 1]]);
13455 chk = t;
13456 p[0] = (duk_uint8_t) t;
13457 t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 2]]) |
13458 ((duk_int_t) duk_hex_dectab[inp[i + 3]]);
13459 chk |= t;
13460 p[1] = (duk_uint8_t) t;
13461 t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 4]]) |
13462 ((duk_int_t) duk_hex_dectab[inp[i + 5]]);
13463 chk |= t;
13464 p[2] = (duk_uint8_t) t;
13465 t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 6]]) |
13466 ((duk_int_t) duk_hex_dectab[inp[i + 7]]);
13467 chk |= t;
13468 p[3] = (duk_uint8_t) t;
13469 p += 4;
13470
13471 /* Check if any lookup above had a negative result. */
13472 if (DUK_UNLIKELY(chk < 0)) {
13473 goto type_error;
13474 }
13475 }
13476 for (; i < len; i += 2) {
13477 t = (((duk_int_t) duk_hex_dectab[inp[i]]) << 4) |
13478 ((duk_int_t) duk_hex_dectab[inp[i + 1]]);
13479 if (DUK_UNLIKELY(t < 0)) {
13480 goto type_error;
13481 }
13482 *p++ = (duk_uint8_t) t;
13483 }
13484#else /* DUK_USE_HEX_FASTPATH */
7c673cae
FG
13485 for (i = 0; i < len; i += 2) {
13486 /* For invalid characters the value -1 gets extended to
13487 * at least 16 bits. If either nybble is invalid, the
13488 * resulting 't' will be < 0.
13489 */
11fdf7f2
TL
13490 t = (((duk_int_t) duk_hex_dectab[inp[i]]) << 4) |
13491 ((duk_int_t) duk_hex_dectab[inp[i + 1]]);
7c673cae
FG
13492 if (DUK_UNLIKELY(t < 0)) {
13493 goto type_error;
13494 }
13495 buf[i >> 1] = (duk_uint8_t) t;
13496 }
11fdf7f2 13497#endif /* DUK_USE_HEX_FASTPATH */
7c673cae
FG
13498
13499 duk_replace(ctx, index);
13500 return;
13501
13502 type_error:
11fdf7f2 13503 DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED);
7c673cae
FG
13504}
13505
13506DUK_EXTERNAL const char *duk_json_encode(duk_context *ctx, duk_idx_t index) {
13507#ifdef DUK_USE_ASSERTIONS
13508 duk_idx_t top_at_entry;
13509#endif
13510 const char *ret;
13511
13512 DUK_ASSERT_CTX_VALID(ctx);
13513#ifdef DUK_USE_ASSERTIONS
13514 top_at_entry = duk_get_top(ctx);
13515#endif
13516
13517 index = duk_require_normalize_index(ctx, index);
13518 duk_bi_json_stringify_helper(ctx,
13519 index /*idx_value*/,
13520 DUK_INVALID_INDEX /*idx_replacer*/,
13521 DUK_INVALID_INDEX /*idx_space*/,
13522 0 /*flags*/);
13523 DUK_ASSERT(duk_is_string(ctx, -1));
13524 duk_replace(ctx, index);
13525 ret = duk_get_string(ctx, index);
13526
13527 DUK_ASSERT(duk_get_top(ctx) == top_at_entry);
13528
13529 return ret;
13530}
13531
13532DUK_EXTERNAL void duk_json_decode(duk_context *ctx, duk_idx_t index) {
13533#ifdef DUK_USE_ASSERTIONS
13534 duk_idx_t top_at_entry;
13535#endif
13536
13537 DUK_ASSERT_CTX_VALID(ctx);
13538#ifdef DUK_USE_ASSERTIONS
13539 top_at_entry = duk_get_top(ctx);
13540#endif
13541
13542 index = duk_require_normalize_index(ctx, index);
13543 duk_bi_json_parse_helper(ctx,
13544 index /*idx_value*/,
13545 DUK_INVALID_INDEX /*idx_reviver*/,
13546 0 /*flags*/);
13547 duk_replace(ctx, index);
13548
13549 DUK_ASSERT(duk_get_top(ctx) == top_at_entry);
13550}
7c673cae
FG
13551/*
13552 * Compilation and evaluation
13553 */
13554
13555/* include removed: duk_internal.h */
13556
13557typedef struct duk__compile_raw_args duk__compile_raw_args;
13558struct duk__compile_raw_args {
13559 duk_size_t src_length; /* should be first on 64-bit platforms */
13560 const duk_uint8_t *src_buffer;
13561 duk_uint_t flags;
13562};
13563
13564/* Eval is just a wrapper now. */
13565DUK_EXTERNAL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) {
13566 duk_uint_t comp_flags;
13567 duk_int_t rc;
13568
13569 DUK_ASSERT_CTX_VALID(ctx);
13570
13571 /* Note: strictness is *not* inherited from the current Duktape/C.
13572 * This would be confusing because the current strictness state
13573 * depends on whether we're running inside a Duktape/C activation
13574 * (= strict mode) or outside of any activation (= non-strict mode).
13575 * See tests/api/test-eval-strictness.c for more discussion.
13576 */
13577
11fdf7f2 13578 /* [ ... source? filename? ] (depends on flags) */
7c673cae
FG
13579
13580 comp_flags = flags;
13581 comp_flags |= DUK_COMPILE_EVAL;
13582 rc = duk_compile_raw(ctx, src_buffer, src_length, comp_flags); /* may be safe, or non-safe depending on flags */
13583
13584 /* [ ... closure/error ] */
13585
13586 if (rc != DUK_EXEC_SUCCESS) {
13587 rc = DUK_EXEC_ERROR;
13588 goto got_rc;
13589 }
13590
13591 duk_push_global_object(ctx); /* explicit 'this' binding, see GH-164 */
13592
13593 if (flags & DUK_COMPILE_SAFE) {
13594 rc = duk_pcall_method(ctx, 0);
13595 } else {
13596 duk_call_method(ctx, 0);
13597 rc = DUK_EXEC_SUCCESS;
13598 }
13599
13600 /* [ ... result/error ] */
13601
13602 got_rc:
13603 if (flags & DUK_COMPILE_NORESULT) {
13604 duk_pop(ctx);
13605 }
13606
13607 return rc;
13608}
13609
13610/* Helper which can be called both directly and with duk_safe_call(). */
13611DUK_LOCAL duk_ret_t duk__do_compile(duk_context *ctx) {
13612 duk_hthread *thr = (duk_hthread *) ctx;
13613 duk__compile_raw_args *comp_args;
13614 duk_uint_t flags;
13615 duk_small_uint_t comp_flags;
13616 duk_hcompiledfunction *h_templ;
13617
13618 DUK_ASSERT_CTX_VALID(ctx);
13619
13620 /* Note: strictness is not inherited from the current Duktape/C
13621 * context. Otherwise it would not be possible to compile
13622 * non-strict code inside a Duktape/C activation (which is
13623 * always strict now). See tests/api/test-eval-strictness.c
13624 * for discussion.
13625 */
13626
11fdf7f2 13627 /* [ ... source? filename? &comp_args ] (depends on flags) */
7c673cae
FG
13628
13629 comp_args = (duk__compile_raw_args *) duk_require_pointer(ctx, -1);
13630 flags = comp_args->flags;
13631 duk_pop(ctx);
13632
11fdf7f2
TL
13633 /* [ ... source? filename? ] */
13634
13635 if (flags & DUK_COMPILE_NOFILENAME) {
13636 /* Automatic filename: 'eval' or 'input'. */
13637 duk_push_hstring_stridx(ctx, (flags & DUK_COMPILE_EVAL) ? DUK_STRIDX_EVAL : DUK_STRIDX_INPUT);
13638 }
13639
7c673cae
FG
13640 /* [ ... source? filename ] */
13641
13642 if (!comp_args->src_buffer) {
13643 duk_hstring *h_sourcecode;
13644
13645 h_sourcecode = duk_get_hstring(ctx, -2);
13646 if ((flags & DUK_COMPILE_NOSOURCE) || /* args incorrect */
13647 (h_sourcecode == NULL)) { /* e.g. duk_push_string_file_raw() pushed undefined */
13648 /* XXX: when this error is caused by a nonexistent
13649 * file given to duk_peval_file() or similar, the
13650 * error message is not the best possible.
13651 */
11fdf7f2 13652 DUK_ERROR_API(thr, DUK_STR_NO_SOURCECODE);
7c673cae
FG
13653 }
13654 DUK_ASSERT(h_sourcecode != NULL);
13655 comp_args->src_buffer = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode);
13656 comp_args->src_length = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode);
13657 }
13658 DUK_ASSERT(comp_args->src_buffer != NULL);
13659
13660 /* XXX: unnecessary translation of flags */
13661 comp_flags = 0;
13662 if (flags & DUK_COMPILE_EVAL) {
13663 comp_flags |= DUK_JS_COMPILE_FLAG_EVAL;
13664 }
13665 if (flags & DUK_COMPILE_FUNCTION) {
13666 comp_flags |= DUK_JS_COMPILE_FLAG_EVAL |
13667 DUK_JS_COMPILE_FLAG_FUNCEXPR;
13668 }
13669 if (flags & DUK_COMPILE_STRICT) {
13670 comp_flags |= DUK_JS_COMPILE_FLAG_STRICT;
13671 }
13672
13673 /* [ ... source? filename ] */
13674
13675 duk_js_compile(thr, comp_args->src_buffer, comp_args->src_length, comp_flags);
13676
13677 /* [ ... source? func_template ] */
13678
13679 if (flags & DUK_COMPILE_NOSOURCE) {
13680 ;
13681 } else {
13682 duk_remove(ctx, -2);
13683 }
13684
13685 /* [ ... func_template ] */
13686
13687 h_templ = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);
13688 DUK_ASSERT(h_templ != NULL);
13689 duk_js_push_closure(thr,
13690 h_templ,
13691 thr->builtins[DUK_BIDX_GLOBAL_ENV],
11fdf7f2
TL
13692 thr->builtins[DUK_BIDX_GLOBAL_ENV],
13693 1 /*add_auto_proto*/);
7c673cae
FG
13694 duk_remove(ctx, -2); /* -> [ ... closure ] */
13695
13696 /* [ ... closure ] */
13697
13698 return 1;
13699}
13700
13701DUK_EXTERNAL duk_int_t duk_compile_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) {
13702 duk__compile_raw_args comp_args_alloc;
13703 duk__compile_raw_args *comp_args = &comp_args_alloc;
13704
13705 DUK_ASSERT_CTX_VALID(ctx);
13706
13707 if ((flags & DUK_COMPILE_STRLEN) && (src_buffer != NULL)) {
13708 /* String length is computed here to avoid multiple evaluation
13709 * of a macro argument in the calling side.
13710 */
13711 src_length = DUK_STRLEN(src_buffer);
13712 }
13713
13714 comp_args->src_buffer = (const duk_uint8_t *) src_buffer;
13715 comp_args->src_length = src_length;
13716 comp_args->flags = flags;
13717 duk_push_pointer(ctx, (void *) comp_args);
13718
11fdf7f2 13719 /* [ ... source? filename? &comp_args ] (depends on flags) */
7c673cae
FG
13720
13721 if (flags & DUK_COMPILE_SAFE) {
13722 duk_int_t rc;
13723 duk_int_t nargs;
13724 duk_int_t nrets = 1;
13725
11fdf7f2
TL
13726 /* Arguments can be: [ source? filename? &comp_args] so that
13727 * nargs is 1 to 3. Call site encodes the correct nargs count
13728 * directly into flags.
13729 */
13730 nargs = flags & 0x07;
13731 DUK_ASSERT(nargs == (1 +
13732 ((flags & DUK_COMPILE_NOSOURCE) ? 0 : 1) +
13733 ((flags & DUK_COMPILE_NOFILENAME) ? 0 : 1)));
7c673cae
FG
13734 rc = duk_safe_call(ctx, duk__do_compile, nargs, nrets);
13735
13736 /* [ ... closure ] */
13737 return rc;
13738 }
13739
13740 (void) duk__do_compile(ctx);
13741
13742 /* [ ... closure ] */
13743 return DUK_EXEC_SUCCESS;
13744}
7c673cae
FG
13745/*
13746 * Debugging related API calls
13747 */
13748
13749/* include removed: duk_internal.h */
13750
13751DUK_EXTERNAL void duk_push_context_dump(duk_context *ctx) {
13752 duk_idx_t idx;
13753 duk_idx_t top;
13754
13755 DUK_ASSERT_CTX_VALID(ctx);
13756
13757 /* We don't duk_require_stack() here now, but rely on the caller having
13758 * enough space.
13759 */
13760
13761 top = duk_get_top(ctx);
13762 duk_push_array(ctx);
13763 for (idx = 0; idx < top; idx++) {
13764 duk_dup(ctx, idx);
13765 duk_put_prop_index(ctx, -2, idx);
13766 }
13767
13768 /* XXX: conversion errors should not propagate outwards.
13769 * Perhaps values need to be coerced individually?
13770 */
13771 duk_bi_json_stringify_helper(ctx,
13772 duk_get_top_index(ctx), /*idx_value*/
13773 DUK_INVALID_INDEX, /*idx_replacer*/
13774 DUK_INVALID_INDEX, /*idx_space*/
13775 DUK_JSON_FLAG_EXT_CUSTOM |
13776 DUK_JSON_FLAG_ASCII_ONLY |
13777 DUK_JSON_FLAG_AVOID_KEY_QUOTES /*flags*/);
13778
13779 duk_push_sprintf(ctx, "ctx: top=%ld, stack=%s", (long) top, (const char *) duk_safe_to_string(ctx, -1));
13780 duk_replace(ctx, -3); /* [ ... arr jsonx(arr) res ] -> [ ... res jsonx(arr) ] */
13781 duk_pop(ctx);
13782 DUK_ASSERT(duk_is_string(ctx, -1));
13783}
13784
13785#if defined(DUK_USE_DEBUGGER_SUPPORT)
13786
11fdf7f2
TL
13787DUK_EXTERNAL void duk_debugger_attach_custom(duk_context *ctx,
13788 duk_debug_read_function read_cb,
13789 duk_debug_write_function write_cb,
13790 duk_debug_peek_function peek_cb,
13791 duk_debug_read_flush_function read_flush_cb,
13792 duk_debug_write_flush_function write_flush_cb,
13793 duk_debug_request_function request_cb,
13794 duk_debug_detached_function detached_cb,
13795 void *udata) {
7c673cae
FG
13796 duk_hthread *thr = (duk_hthread *) ctx;
13797 duk_heap *heap;
13798 const char *str;
13799 duk_size_t len;
13800
11fdf7f2
TL
13801 /* XXX: should there be an error or an automatic detach if
13802 * already attached?
13803 */
13804
13805 DUK_D(DUK_DPRINT("application called duk_debugger_attach()"));
13806
7c673cae
FG
13807 DUK_ASSERT_CTX_VALID(ctx);
13808 DUK_ASSERT(read_cb != NULL);
13809 DUK_ASSERT(write_cb != NULL);
13810 /* Other callbacks are optional. */
13811
13812 heap = thr->heap;
13813 heap->dbg_read_cb = read_cb;
13814 heap->dbg_write_cb = write_cb;
13815 heap->dbg_peek_cb = peek_cb;
13816 heap->dbg_read_flush_cb = read_flush_cb;
13817 heap->dbg_write_flush_cb = write_flush_cb;
11fdf7f2 13818 heap->dbg_request_cb = request_cb;
7c673cae
FG
13819 heap->dbg_detached_cb = detached_cb;
13820 heap->dbg_udata = udata;
11fdf7f2 13821 heap->dbg_have_next_byte = 0;
7c673cae
FG
13822
13823 /* Start in paused state. */
13824 heap->dbg_processing = 0;
13825 heap->dbg_paused = 1;
13826 heap->dbg_state_dirty = 1;
13827 heap->dbg_force_restart = 0;
13828 heap->dbg_step_type = 0;
13829 heap->dbg_step_thread = NULL;
13830 heap->dbg_step_csindex = 0;
13831 heap->dbg_step_startline = 0;
13832 heap->dbg_exec_counter = 0;
13833 heap->dbg_last_counter = 0;
13834 heap->dbg_last_time = 0.0;
13835
13836 /* Send version identification and flush right afterwards. Note that
13837 * we must write raw, unframed bytes here.
13838 */
13839 duk_push_sprintf(ctx, "%ld %ld %s %s\n",
13840 (long) DUK_DEBUG_PROTOCOL_VERSION,
13841 (long) DUK_VERSION,
13842 (const char *) DUK_GIT_DESCRIBE,
13843 (const char *) DUK_USE_TARGET_INFO);
13844 str = duk_get_lstring(ctx, -1, &len);
13845 DUK_ASSERT(str != NULL);
13846 duk_debug_write_bytes(thr, (const duk_uint8_t *) str, len);
13847 duk_debug_write_flush(thr);
13848 duk_pop(ctx);
13849}
13850
13851DUK_EXTERNAL void duk_debugger_detach(duk_context *ctx) {
13852 duk_hthread *thr;
13853
11fdf7f2
TL
13854 DUK_D(DUK_DPRINT("application called duk_debugger_detach()"));
13855
7c673cae
FG
13856 DUK_ASSERT_CTX_VALID(ctx);
13857 thr = (duk_hthread *) ctx;
13858 DUK_ASSERT(thr != NULL);
13859 DUK_ASSERT(thr->heap != NULL);
13860
11fdf7f2 13861 /* Can be called multiple times with no harm. */
7c673cae
FG
13862 duk_debug_do_detach(thr->heap);
13863}
13864
13865DUK_EXTERNAL void duk_debugger_cooperate(duk_context *ctx) {
13866 duk_hthread *thr;
13867 duk_bool_t processed_messages;
13868
13869 DUK_ASSERT_CTX_VALID(ctx);
13870 thr = (duk_hthread *) ctx;
13871 DUK_ASSERT(thr != NULL);
13872 DUK_ASSERT(thr->heap != NULL);
13873
13874 if (!DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
13875 return;
13876 }
13877 if (thr->callstack_top > 0 || thr->heap->dbg_processing) {
13878 /* Calling duk_debugger_cooperate() while Duktape is being
13879 * called into is not supported. This is not a 100% check
13880 * but prevents any damage in most cases.
13881 */
13882 return;
13883 }
13884
7c673cae 13885 processed_messages = duk_debug_process_messages(thr, 1 /*no_block*/);
7c673cae
FG
13886 DUK_UNREF(processed_messages);
13887}
13888
11fdf7f2
TL
13889DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_context *ctx, duk_idx_t nvalues) {
13890 duk_hthread *thr;
13891 duk_idx_t top;
13892 duk_idx_t idx;
13893 duk_bool_t ret = 0;
13894
13895 DUK_ASSERT_CTX_VALID(ctx);
13896 thr = (duk_hthread *) ctx;
13897 DUK_ASSERT(thr != NULL);
13898 DUK_ASSERT(thr->heap != NULL);
13899
13900 DUK_D(DUK_DPRINT("application called duk_debugger_notify() with nvalues=%ld", (long) nvalues));
13901
13902 top = duk_get_top(ctx);
13903 if (top < nvalues) {
13904 DUK_ERROR_API(thr, "not enough stack values for notify");
13905 return ret; /* unreachable */
13906 }
13907 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
13908 duk_debug_write_notify(thr, DUK_DBG_CMD_APPNOTIFY);
13909 for (idx = top - nvalues; idx < top; idx++) {
13910 duk_tval *tv = DUK_GET_TVAL_POSIDX(ctx, idx);
13911 duk_debug_write_tval(thr, tv);
13912 }
13913 duk_debug_write_eom(thr);
13914
13915 /* Return non-zero (true) if we have a good reason to believe
13916 * the notify was delivered; if we're still attached at least
13917 * a transport error was not indicated by the transport write
13918 * callback. This is not a 100% guarantee of course.
13919 */
13920 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
13921 ret = 1;
13922 }
13923 }
13924 duk_pop_n(ctx, nvalues);
13925 return ret;
13926}
13927
13928DUK_EXTERNAL void duk_debugger_pause(duk_context *ctx) {
13929 duk_hthread *thr;
13930
13931 DUK_ASSERT_CTX_VALID(ctx);
13932 thr = (duk_hthread *) ctx;
13933 DUK_ASSERT(thr != NULL);
13934 DUK_ASSERT(thr->heap != NULL);
13935
13936 DUK_D(DUK_DPRINT("application called duk_debugger_pause()"));
13937
13938 /* Treat like a debugger statement: ignore when not attached. */
13939 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
13940 DUK_HEAP_SET_PAUSED(thr->heap);
13941
13942 /* Pause on the next opcode executed. This is always safe to do even
13943 * inside the debugger message loop: the interrupt counter will be reset
13944 * to its proper value when the message loop exits.
13945 */
13946 thr->interrupt_init = 1;
13947 thr->interrupt_counter = 0;
13948 }
13949}
13950
7c673cae
FG
13951#else /* DUK_USE_DEBUGGER_SUPPORT */
13952
11fdf7f2
TL
13953DUK_EXTERNAL void duk_debugger_attach_custom(duk_context *ctx,
13954 duk_debug_read_function read_cb,
13955 duk_debug_write_function write_cb,
13956 duk_debug_peek_function peek_cb,
13957 duk_debug_read_flush_function read_flush_cb,
13958 duk_debug_write_flush_function write_flush_cb,
13959 duk_debug_request_function request_cb,
13960 duk_debug_detached_function detached_cb,
13961 void *udata) {
7c673cae
FG
13962 DUK_ASSERT_CTX_VALID(ctx);
13963 DUK_UNREF(read_cb);
13964 DUK_UNREF(write_cb);
13965 DUK_UNREF(peek_cb);
13966 DUK_UNREF(read_flush_cb);
13967 DUK_UNREF(write_flush_cb);
11fdf7f2 13968 DUK_UNREF(request_cb);
7c673cae
FG
13969 DUK_UNREF(detached_cb);
13970 DUK_UNREF(udata);
11fdf7f2 13971 DUK_ERROR_API((duk_hthread *) ctx, "no debugger support");
7c673cae
FG
13972}
13973
13974DUK_EXTERNAL void duk_debugger_detach(duk_context *ctx) {
13975 DUK_ASSERT_CTX_VALID(ctx);
11fdf7f2 13976 DUK_ERROR_API((duk_hthread *) ctx, "no debugger support");
7c673cae
FG
13977}
13978
13979DUK_EXTERNAL void duk_debugger_cooperate(duk_context *ctx) {
13980 /* nop */
13981 DUK_ASSERT_CTX_VALID(ctx);
13982 DUK_UNREF(ctx);
13983}
13984
11fdf7f2
TL
13985DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_context *ctx, duk_idx_t nvalues) {
13986 duk_idx_t top;
13987
13988 DUK_ASSERT_CTX_VALID(ctx);
13989
13990 top = duk_get_top(ctx);
13991 if (top < nvalues) {
13992 DUK_ERROR_API((duk_hthread *) ctx, "not enough stack values for notify");
13993 return 0; /* unreachable */
13994 }
13995
13996 /* No debugger support, just pop values. */
13997 duk_pop_n(ctx, nvalues);
13998 return 0;
13999}
14000
14001DUK_EXTERNAL void duk_debugger_pause(duk_context *ctx) {
14002 /* Treat like debugger statement: nop */
14003 DUK_ASSERT_CTX_VALID(ctx);
14004 DUK_UNREF(ctx);
14005}
14006
7c673cae 14007#endif /* DUK_USE_DEBUGGER_SUPPORT */
7c673cae
FG
14008/*
14009 * Heap creation and destruction
14010 */
14011
14012/* include removed: duk_internal.h */
14013
11fdf7f2
TL
14014typedef struct duk_internal_thread_state duk_internal_thread_state;
14015
14016struct duk_internal_thread_state {
14017 duk_ljstate lj;
14018 duk_bool_t handling_error;
14019 duk_hthread *curr_thread;
14020 duk_int_t call_recursion_depth;
14021};
14022
7c673cae
FG
14023DUK_EXTERNAL
14024duk_context *duk_create_heap(duk_alloc_function alloc_func,
14025 duk_realloc_function realloc_func,
14026 duk_free_function free_func,
14027 void *heap_udata,
14028 duk_fatal_function fatal_handler) {
14029 duk_heap *heap = NULL;
14030 duk_context *ctx;
14031
14032 /* Assume that either all memory funcs are NULL or non-NULL, mixed
14033 * cases will now be unsafe.
14034 */
14035
14036 /* XXX: just assert non-NULL values here and make caller arguments
14037 * do the defaulting to the default implementations (smaller code)?
14038 */
14039
14040 if (!alloc_func) {
14041 DUK_ASSERT(realloc_func == NULL);
14042 DUK_ASSERT(free_func == NULL);
11fdf7f2 14043#if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS)
7c673cae
FG
14044 alloc_func = duk_default_alloc_function;
14045 realloc_func = duk_default_realloc_function;
14046 free_func = duk_default_free_function;
11fdf7f2
TL
14047#else
14048 DUK_D(DUK_DPRINT("no allocation functions given and no default providers"));
14049 return NULL;
14050#endif
7c673cae
FG
14051 } else {
14052 DUK_ASSERT(realloc_func != NULL);
14053 DUK_ASSERT(free_func != NULL);
14054 }
14055
14056 if (!fatal_handler) {
14057 fatal_handler = duk_default_fatal_handler;
14058 }
14059
14060 DUK_ASSERT(alloc_func != NULL);
14061 DUK_ASSERT(realloc_func != NULL);
14062 DUK_ASSERT(free_func != NULL);
14063 DUK_ASSERT(fatal_handler != NULL);
14064
14065 heap = duk_heap_alloc(alloc_func, realloc_func, free_func, heap_udata, fatal_handler);
14066 if (!heap) {
14067 return NULL;
14068 }
14069 ctx = (duk_context *) heap->heap_thread;
14070 DUK_ASSERT(ctx != NULL);
14071 DUK_ASSERT(((duk_hthread *) ctx)->heap != NULL);
14072 return ctx;
14073}
14074
14075DUK_EXTERNAL void duk_destroy_heap(duk_context *ctx) {
14076 duk_hthread *thr = (duk_hthread *) ctx;
14077 duk_heap *heap;
14078
14079 if (!ctx) {
14080 return;
14081 }
14082 heap = thr->heap;
14083 DUK_ASSERT(heap != NULL);
14084
14085 duk_heap_free(heap);
14086}
14087
11fdf7f2
TL
14088DUK_EXTERNAL void duk_suspend(duk_context *ctx, duk_thread_state *state) {
14089 duk_hthread *thr = (duk_hthread *) ctx;
14090 duk_internal_thread_state *snapshot = (duk_internal_thread_state *) (void *) state;
14091 duk_heap *heap;
14092 duk_ljstate *lj;
14093
14094 DUK_ASSERT_CTX_VALID(ctx);
14095 DUK_ASSERT(thr != NULL);
14096 DUK_ASSERT(thr->heap != NULL);
14097 DUK_ASSERT(state != NULL); /* unvalidated */
14098
14099 heap = thr->heap;
14100 lj = &heap->lj;
14101
14102 duk_push_tval(ctx, &lj->value1);
14103 duk_push_tval(ctx, &lj->value2);
14104
14105 DUK_MEMCPY((void *) &snapshot->lj, (const void *) lj, sizeof(duk_ljstate));
14106 snapshot->handling_error = heap->handling_error;
14107 snapshot->curr_thread = heap->curr_thread;
14108 snapshot->call_recursion_depth = heap->call_recursion_depth;
14109
14110 lj->jmpbuf_ptr = NULL;
14111 lj->type = DUK_LJ_TYPE_UNKNOWN;
14112 DUK_TVAL_SET_UNDEFINED(&lj->value1);
14113 DUK_TVAL_SET_UNDEFINED(&lj->value2);
14114 heap->handling_error = 0;
14115 heap->curr_thread = NULL;
14116 heap->call_recursion_depth = 0;
14117}
14118
14119DUK_EXTERNAL void duk_resume(duk_context *ctx, const duk_thread_state *state) {
14120 duk_hthread *thr = (duk_hthread *) ctx;
14121 const duk_internal_thread_state *snapshot = (const duk_internal_thread_state *) (const void *) state;
14122 duk_heap *heap;
14123
14124 DUK_ASSERT_CTX_VALID(ctx);
14125 DUK_ASSERT(thr != NULL);
14126 DUK_ASSERT(thr->heap != NULL);
14127 DUK_ASSERT(state != NULL); /* unvalidated */
14128
14129 heap = thr->heap;
14130
14131 DUK_MEMCPY((void *) &heap->lj, (const void *) &snapshot->lj, sizeof(duk_ljstate));
14132 heap->handling_error = snapshot->handling_error;
14133 heap->curr_thread = snapshot->curr_thread;
14134 heap->call_recursion_depth = snapshot->call_recursion_depth;
14135
14136 duk_pop_2(ctx);
14137}
14138
7c673cae
FG
14139/* XXX: better place for this */
14140DUK_EXTERNAL void duk_set_global_object(duk_context *ctx) {
14141 duk_hthread *thr = (duk_hthread *) ctx;
14142 duk_hobject *h_glob;
14143 duk_hobject *h_prev_glob;
14144 duk_hobject *h_env;
14145 duk_hobject *h_prev_env;
14146
14147 DUK_D(DUK_DPRINT("replace global object with: %!T", duk_get_tval(ctx, -1)));
14148
14149 h_glob = duk_require_hobject(ctx, -1);
14150 DUK_ASSERT(h_glob != NULL);
14151
14152 /*
14153 * Replace global object.
14154 */
14155
14156 h_prev_glob = thr->builtins[DUK_BIDX_GLOBAL];
11fdf7f2 14157 DUK_UNREF(h_prev_glob);
7c673cae
FG
14158 thr->builtins[DUK_BIDX_GLOBAL] = h_glob;
14159 DUK_HOBJECT_INCREF(thr, h_glob);
14160 DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_prev_glob); /* side effects, in theory (referenced by global env) */
14161
14162 /*
14163 * Replace lexical environment for global scope
14164 *
14165 * Create a new object environment for the global lexical scope.
14166 * We can't just reset the _Target property of the current one,
14167 * because the lexical scope is shared by other threads with the
14168 * same (initial) built-ins.
14169 */
14170
14171 (void) duk_push_object_helper(ctx,
14172 DUK_HOBJECT_FLAG_EXTENSIBLE |
14173 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV),
14174 -1); /* no prototype, updated below */
14175
14176 duk_dup(ctx, -2);
14177 duk_dup(ctx, -3);
14178
14179 /* [ ... new_glob new_env new_glob new_glob ] */
14180
14181 duk_xdef_prop_stridx(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
14182 duk_xdef_prop_stridx(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE);
14183
14184 /* [ ... new_glob new_env ] */
14185
14186 h_env = duk_get_hobject(ctx, -1);
14187 DUK_ASSERT(h_env != NULL);
14188
14189 h_prev_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
14190 thr->builtins[DUK_BIDX_GLOBAL_ENV] = h_env;
14191 DUK_HOBJECT_INCREF(thr, h_env);
14192 DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_prev_env); /* side effects */
14193 DUK_UNREF(h_env); /* without refcounts */
14194 DUK_UNREF(h_prev_env);
14195
14196 /* [ ... new_glob new_env ] */
14197
14198 duk_pop_2(ctx);
14199
14200 /* [ ... ] */
14201}
7c673cae
FG
14202/*
14203 * Logging
14204 *
14205 * Current logging primitive is a sprintf-style log which is convenient
14206 * for most C code. Another useful primitive would be to log N arguments
14207 * from value stack (like the Ecmascript binding does).
14208 */
14209
14210/* include removed: duk_internal.h */
14211
14212DUK_EXTERNAL void duk_log_va(duk_context *ctx, duk_int_t level, const char *fmt, va_list ap) {
14213 /* stridx_logfunc[] must be static to allow initializer with old compilers like BCC */
14214 static const duk_uint16_t stridx_logfunc[6] = {
14215 DUK_STRIDX_LC_TRACE, DUK_STRIDX_LC_DEBUG, DUK_STRIDX_LC_INFO,
14216 DUK_STRIDX_LC_WARN, DUK_STRIDX_LC_ERROR, DUK_STRIDX_LC_FATAL
14217 };
14218
14219 DUK_ASSERT_CTX_VALID(ctx);
14220
14221 if (level < 0) {
14222 level = 0;
14223 } else if (level > (int) (sizeof(stridx_logfunc) / sizeof(duk_uint16_t)) - 1) {
14224 level = (int) (sizeof(stridx_logfunc) / sizeof(duk_uint16_t)) - 1;
14225 }
14226
14227 duk_push_hobject_bidx(ctx, DUK_BIDX_LOGGER_CONSTRUCTOR);
14228 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_CLOG);
14229 duk_get_prop_stridx(ctx, -1, stridx_logfunc[level]);
14230 duk_dup(ctx, -2);
14231
14232 /* [ ... Logger clog logfunc clog ] */
14233
14234 duk_push_vsprintf(ctx, fmt, ap);
14235
14236 /* [ ... Logger clog logfunc clog(=this) msg ] */
14237
14238 duk_call_method(ctx, 1 /*nargs*/);
14239
14240 /* [ ... Logger clog res ] */
14241
14242 duk_pop_3(ctx);
14243}
14244
14245DUK_EXTERNAL void duk_log(duk_context *ctx, duk_int_t level, const char *fmt, ...) {
14246 va_list ap;
14247
14248 DUK_ASSERT_CTX_VALID(ctx);
14249
14250 va_start(ap, fmt);
14251 duk_log_va(ctx, level, fmt, ap);
14252 va_end(ap);
14253}
7c673cae
FG
14254/*
14255 * Memory calls.
14256 */
14257
14258/* include removed: duk_internal.h */
14259
14260DUK_EXTERNAL void *duk_alloc_raw(duk_context *ctx, duk_size_t size) {
14261 duk_hthread *thr = (duk_hthread *) ctx;
14262
14263 DUK_ASSERT_CTX_VALID(ctx);
14264
14265 return DUK_ALLOC_RAW(thr->heap, size);
14266}
14267
14268DUK_EXTERNAL void duk_free_raw(duk_context *ctx, void *ptr) {
14269 duk_hthread *thr = (duk_hthread *) ctx;
14270
14271 DUK_ASSERT_CTX_VALID(ctx);
14272
14273 DUK_FREE_RAW(thr->heap, ptr);
14274}
14275
14276DUK_EXTERNAL void *duk_realloc_raw(duk_context *ctx, void *ptr, duk_size_t size) {
14277 duk_hthread *thr = (duk_hthread *) ctx;
14278
14279 DUK_ASSERT_CTX_VALID(ctx);
14280
14281 return DUK_REALLOC_RAW(thr->heap, ptr, size);
14282}
14283
14284DUK_EXTERNAL void *duk_alloc(duk_context *ctx, duk_size_t size) {
14285 duk_hthread *thr = (duk_hthread *) ctx;
14286
14287 DUK_ASSERT_CTX_VALID(ctx);
14288
14289 return DUK_ALLOC(thr->heap, size);
14290}
14291
14292DUK_EXTERNAL void duk_free(duk_context *ctx, void *ptr) {
14293 duk_hthread *thr = (duk_hthread *) ctx;
14294
14295 DUK_ASSERT_CTX_VALID(ctx);
14296
14297 DUK_FREE(thr->heap, ptr);
14298}
14299
14300DUK_EXTERNAL void *duk_realloc(duk_context *ctx, void *ptr, duk_size_t size) {
14301 duk_hthread *thr = (duk_hthread *) ctx;
14302
14303 DUK_ASSERT_CTX_VALID(ctx);
14304
14305 /*
14306 * Note: since this is an exposed API call, there should be
14307 * no way a mark-and-sweep could have a side effect on the
14308 * memory allocation behind 'ptr'; the pointer should never
14309 * be something that Duktape wants to change.
14310 *
14311 * Thus, no need to use DUK_REALLOC_INDIRECT (and we don't
14312 * have the storage location here anyway).
14313 */
14314
14315 return DUK_REALLOC(thr->heap, ptr, size);
14316}
14317
14318DUK_EXTERNAL void duk_get_memory_functions(duk_context *ctx, duk_memory_functions *out_funcs) {
14319 duk_hthread *thr = (duk_hthread *) ctx;
14320 duk_heap *heap;
14321
14322 DUK_ASSERT_CTX_VALID(ctx);
14323 DUK_ASSERT(out_funcs != NULL);
14324 DUK_ASSERT(thr != NULL);
14325 DUK_ASSERT(thr->heap != NULL);
14326
14327 heap = thr->heap;
14328 out_funcs->alloc_func = heap->alloc_func;
14329 out_funcs->realloc_func = heap->realloc_func;
14330 out_funcs->free_func = heap->free_func;
14331 out_funcs->udata = heap->heap_udata;
14332}
14333
14334DUK_EXTERNAL void duk_gc(duk_context *ctx, duk_uint_t flags) {
14335#ifdef DUK_USE_MARK_AND_SWEEP
14336 duk_hthread *thr = (duk_hthread *) ctx;
14337 duk_heap *heap;
14338
14339 DUK_UNREF(flags);
14340
14341 /* NULL accepted */
14342 if (!ctx) {
14343 return;
14344 }
14345 DUK_ASSERT_CTX_VALID(ctx);
14346 heap = thr->heap;
14347 DUK_ASSERT(heap != NULL);
14348
14349 DUK_D(DUK_DPRINT("mark-and-sweep requested by application"));
14350 duk_heap_mark_and_sweep(heap, 0);
14351#else
14352 DUK_D(DUK_DPRINT("mark-and-sweep requested by application but mark-and-sweep not enabled, ignoring"));
14353 DUK_UNREF(ctx);
14354 DUK_UNREF(flags);
14355#endif
14356}
7c673cae
FG
14357/*
14358 * Object handling: property access and other support functions.
14359 */
14360
14361/* include removed: duk_internal.h */
14362
14363/*
14364 * Property handling
14365 *
14366 * The API exposes only the most common property handling functions.
14367 * The caller can invoke Ecmascript built-ins for full control (e.g.
14368 * defineProperty, getOwnPropertyDescriptor).
14369 */
14370
14371DUK_EXTERNAL duk_bool_t duk_get_prop(duk_context *ctx, duk_idx_t obj_index) {
14372 duk_hthread *thr = (duk_hthread *) ctx;
14373 duk_tval *tv_obj;
14374 duk_tval *tv_key;
14375 duk_bool_t rc;
14376
14377 DUK_ASSERT_CTX_VALID(ctx);
14378
14379 /* Note: copying tv_obj and tv_key to locals to shield against a valstack
14380 * resize is not necessary for a property get right now.
14381 */
14382
14383 tv_obj = duk_require_tval(ctx, obj_index);
14384 tv_key = duk_require_tval(ctx, -1);
14385
14386 rc = duk_hobject_getprop(thr, tv_obj, tv_key);
14387 DUK_ASSERT(rc == 0 || rc == 1);
14388 /* a value is left on stack regardless of rc */
14389
14390 duk_remove(ctx, -2); /* remove key */
14391 return rc; /* 1 if property found, 0 otherwise */
14392}
14393
14394DUK_EXTERNAL duk_bool_t duk_get_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key) {
14395 DUK_ASSERT_CTX_VALID(ctx);
14396 DUK_ASSERT(key != NULL);
14397
14398 obj_index = duk_require_normalize_index(ctx, obj_index);
14399 duk_push_string(ctx, key);
14400 return duk_get_prop(ctx, obj_index);
14401}
14402
14403DUK_EXTERNAL duk_bool_t duk_get_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index) {
14404 DUK_ASSERT_CTX_VALID(ctx);
14405
14406 obj_index = duk_require_normalize_index(ctx, obj_index);
14407 duk_push_uarridx(ctx, arr_index);
14408 return duk_get_prop(ctx, obj_index);
14409}
14410
14411DUK_INTERNAL duk_bool_t duk_get_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx) {
14412 duk_hthread *thr = (duk_hthread *) ctx;
14413
14414 DUK_ASSERT_CTX_VALID(ctx);
14415 DUK_ASSERT_DISABLE(stridx >= 0);
14416 DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
11fdf7f2 14417 DUK_UNREF(thr);
7c673cae
FG
14418
14419 obj_index = duk_require_normalize_index(ctx, obj_index);
14420 duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
14421 return duk_get_prop(ctx, obj_index);
14422}
14423
14424DUK_INTERNAL duk_bool_t duk_get_prop_stridx_boolean(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_bool_t *out_has_prop) {
14425 duk_bool_t rc;
14426
14427 DUK_ASSERT_CTX_VALID(ctx);
14428 DUK_ASSERT_DISABLE(stridx >= 0);
14429 DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
14430
14431 rc = duk_get_prop_stridx(ctx, obj_index, stridx);
14432 if (out_has_prop) {
14433 *out_has_prop = rc;
14434 }
14435 rc = duk_to_boolean(ctx, -1);
14436 DUK_ASSERT(rc == 0 || rc == 1);
14437 duk_pop(ctx);
14438 return rc;
14439}
14440
11fdf7f2 14441DUK_LOCAL duk_bool_t duk__put_prop_shared(duk_context *ctx, duk_idx_t obj_idx, duk_idx_t idx_key) {
7c673cae
FG
14442 duk_hthread *thr = (duk_hthread *) ctx;
14443 duk_tval *tv_obj;
14444 duk_tval *tv_key;
14445 duk_tval *tv_val;
14446 duk_small_int_t throw_flag;
14447 duk_bool_t rc;
14448
7c673cae
FG
14449 /* Note: copying tv_obj and tv_key to locals to shield against a valstack
14450 * resize is not necessary for a property put right now (putprop protects
14451 * against it internally).
14452 */
14453
11fdf7f2
TL
14454 /* Key and value indices are either (-2, -1) or (-1, -2). Given idx_key,
14455 * idx_val is always (idx_key ^ 0x01).
14456 */
14457 DUK_ASSERT((idx_key == -2 && (idx_key ^ 1) == -1) ||
14458 (idx_key == -1 && (idx_key ^ 1) == -2));
14459 tv_obj = duk_require_tval(ctx, obj_idx);
14460 tv_key = duk_require_tval(ctx, idx_key);
14461 tv_val = duk_require_tval(ctx, idx_key ^ 1);
7c673cae
FG
14462 throw_flag = duk_is_strict_call(ctx);
14463
14464 rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, throw_flag);
14465 DUK_ASSERT(rc == 0 || rc == 1);
14466
14467 duk_pop_2(ctx); /* remove key and value */
14468 return rc; /* 1 if property found, 0 otherwise */
14469}
14470
11fdf7f2
TL
14471DUK_EXTERNAL duk_bool_t duk_put_prop(duk_context *ctx, duk_idx_t obj_idx) {
14472 DUK_ASSERT_CTX_VALID(ctx);
14473 return duk__put_prop_shared(ctx, obj_idx, -2);
14474}
14475
14476DUK_EXTERNAL duk_bool_t duk_put_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key) {
7c673cae
FG
14477 DUK_ASSERT_CTX_VALID(ctx);
14478 DUK_ASSERT(key != NULL);
14479
11fdf7f2
TL
14480 /* Careful here and with other duk_put_prop_xxx() helpers: the
14481 * target object and the property value may be in the same value
14482 * stack slot (unusual, but still conceptually clear).
14483 */
14484 obj_idx = duk_normalize_index(ctx, obj_idx);
14485 (void) duk_push_string(ctx, key);
14486 return duk__put_prop_shared(ctx, obj_idx, -1);
7c673cae
FG
14487}
14488
11fdf7f2 14489DUK_EXTERNAL duk_bool_t duk_put_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
7c673cae
FG
14490 DUK_ASSERT_CTX_VALID(ctx);
14491
11fdf7f2
TL
14492 obj_idx = duk_require_normalize_index(ctx, obj_idx);
14493 duk_push_uarridx(ctx, arr_idx);
14494 return duk__put_prop_shared(ctx, obj_idx, -1);
7c673cae
FG
14495}
14496
11fdf7f2 14497DUK_INTERNAL duk_bool_t duk_put_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_int_t stridx) {
7c673cae
FG
14498 duk_hthread *thr = (duk_hthread *) ctx;
14499
14500 DUK_ASSERT_CTX_VALID(ctx);
14501 DUK_ASSERT_DISABLE(stridx >= 0);
14502 DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
11fdf7f2 14503 DUK_UNREF(thr);
7c673cae 14504
11fdf7f2 14505 obj_idx = duk_require_normalize_index(ctx, obj_idx);
7c673cae 14506 duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
11fdf7f2 14507 return duk__put_prop_shared(ctx, obj_idx, -1);
7c673cae
FG
14508}
14509
14510DUK_EXTERNAL duk_bool_t duk_del_prop(duk_context *ctx, duk_idx_t obj_index) {
14511 duk_hthread *thr = (duk_hthread *) ctx;
14512 duk_tval *tv_obj;
14513 duk_tval *tv_key;
14514 duk_small_int_t throw_flag;
14515 duk_bool_t rc;
14516
14517 DUK_ASSERT_CTX_VALID(ctx);
14518
14519 /* Note: copying tv_obj and tv_key to locals to shield against a valstack
14520 * resize is not necessary for a property delete right now.
14521 */
14522
14523 tv_obj = duk_require_tval(ctx, obj_index);
14524 tv_key = duk_require_tval(ctx, -1);
14525 throw_flag = duk_is_strict_call(ctx);
14526
14527 rc = duk_hobject_delprop(thr, tv_obj, tv_key, throw_flag);
14528 DUK_ASSERT(rc == 0 || rc == 1);
14529
14530 duk_pop(ctx); /* remove key */
14531 return rc;
14532}
14533
14534DUK_EXTERNAL duk_bool_t duk_del_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key) {
14535 DUK_ASSERT_CTX_VALID(ctx);
14536 DUK_ASSERT(key != NULL);
14537
14538 obj_index = duk_require_normalize_index(ctx, obj_index);
14539 duk_push_string(ctx, key);
14540 return duk_del_prop(ctx, obj_index);
14541}
14542
14543DUK_EXTERNAL duk_bool_t duk_del_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index) {
14544 DUK_ASSERT_CTX_VALID(ctx);
14545
14546 obj_index = duk_require_normalize_index(ctx, obj_index);
14547 duk_push_uarridx(ctx, arr_index);
14548 return duk_del_prop(ctx, obj_index);
14549}
14550
14551DUK_INTERNAL duk_bool_t duk_del_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx) {
14552 duk_hthread *thr = (duk_hthread *) ctx;
14553
14554 DUK_ASSERT_CTX_VALID(ctx);
14555 DUK_ASSERT_DISABLE(stridx >= 0);
14556 DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
11fdf7f2 14557 DUK_UNREF(thr);
7c673cae
FG
14558
14559 obj_index = duk_require_normalize_index(ctx, obj_index);
14560 duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
14561 return duk_del_prop(ctx, obj_index);
14562}
14563
14564DUK_EXTERNAL duk_bool_t duk_has_prop(duk_context *ctx, duk_idx_t obj_index) {
14565 duk_hthread *thr = (duk_hthread *) ctx;
14566 duk_tval *tv_obj;
14567 duk_tval *tv_key;
14568 duk_bool_t rc;
14569
14570 DUK_ASSERT_CTX_VALID(ctx);
14571
14572 /* Note: copying tv_obj and tv_key to locals to shield against a valstack
14573 * resize is not necessary for a property existence check right now.
14574 */
14575
14576 tv_obj = duk_require_tval(ctx, obj_index);
14577 tv_key = duk_require_tval(ctx, -1);
14578
14579 rc = duk_hobject_hasprop(thr, tv_obj, tv_key);
14580 DUK_ASSERT(rc == 0 || rc == 1);
14581
14582 duk_pop(ctx); /* remove key */
14583 return rc; /* 1 if property found, 0 otherwise */
14584}
14585
14586DUK_EXTERNAL duk_bool_t duk_has_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key) {
14587 DUK_ASSERT_CTX_VALID(ctx);
14588 DUK_ASSERT(key != NULL);
14589
14590 obj_index = duk_require_normalize_index(ctx, obj_index);
14591 duk_push_string(ctx, key);
14592 return duk_has_prop(ctx, obj_index);
14593}
14594
14595DUK_EXTERNAL duk_bool_t duk_has_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index) {
14596 DUK_ASSERT_CTX_VALID(ctx);
14597
14598 obj_index = duk_require_normalize_index(ctx, obj_index);
14599 duk_push_uarridx(ctx, arr_index);
14600 return duk_has_prop(ctx, obj_index);
14601}
14602
14603DUK_INTERNAL duk_bool_t duk_has_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx) {
14604 duk_hthread *thr = (duk_hthread *) ctx;
14605
14606 DUK_ASSERT_CTX_VALID(ctx);
14607 DUK_ASSERT_DISABLE(stridx >= 0);
14608 DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
11fdf7f2 14609 DUK_UNREF(thr);
7c673cae
FG
14610
14611 obj_index = duk_require_normalize_index(ctx, obj_index);
14612 duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
14613 return duk_has_prop(ctx, obj_index);
14614}
14615
14616/* Define own property without inheritance looks and such. This differs from
14617 * [[DefineOwnProperty]] because special behaviors (like Array 'length') are
14618 * not invoked by this method. The caller must be careful to invoke any such
14619 * behaviors if necessary.
14620 */
14621DUK_INTERNAL void duk_xdef_prop(duk_context *ctx, duk_idx_t obj_index, duk_small_uint_t desc_flags) {
14622 duk_hthread *thr = (duk_hthread *) ctx;
14623 duk_hobject *obj;
14624 duk_hstring *key;
14625
14626 DUK_ASSERT_CTX_VALID(ctx);
14627
14628 obj = duk_require_hobject(ctx, obj_index);
14629 DUK_ASSERT(obj != NULL);
14630 key = duk_to_hstring(ctx, -2);
14631 DUK_ASSERT(key != NULL);
14632 DUK_ASSERT(duk_require_tval(ctx, -1) != NULL);
14633
14634 duk_hobject_define_property_internal(thr, obj, key, desc_flags);
14635
14636 duk_pop(ctx); /* pop key */
14637}
14638
14639DUK_INTERNAL void duk_xdef_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index, duk_small_uint_t desc_flags) {
14640 duk_hthread *thr = (duk_hthread *) ctx;
14641 duk_hobject *obj;
14642
14643 DUK_ASSERT_CTX_VALID(ctx);
14644
14645 obj = duk_require_hobject(ctx, obj_index);
14646 DUK_ASSERT(obj != NULL);
14647
14648 duk_hobject_define_property_internal_arridx(thr, obj, arr_index, desc_flags);
14649 /* value popped by call */
14650}
14651
14652DUK_INTERNAL void duk_xdef_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags) {
14653 duk_hthread *thr = (duk_hthread *) ctx;
14654 duk_hobject *obj;
14655 duk_hstring *key;
14656
14657 DUK_ASSERT_CTX_VALID(ctx);
14658 DUK_ASSERT_DISABLE(stridx >= 0);
14659 DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
14660
14661 obj = duk_require_hobject(ctx, obj_index);
14662 DUK_ASSERT(obj != NULL);
14663 key = DUK_HTHREAD_GET_STRING(thr, stridx);
14664 DUK_ASSERT(key != NULL);
14665 DUK_ASSERT(duk_require_tval(ctx, -1) != NULL);
14666
14667 duk_hobject_define_property_internal(thr, obj, key, desc_flags);
14668 /* value popped by call */
14669}
14670
14671DUK_INTERNAL void duk_xdef_prop_stridx_builtin(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags) {
14672 duk_hthread *thr = (duk_hthread *) ctx;
14673 duk_hobject *obj;
14674 duk_hstring *key;
14675
14676 DUK_ASSERT_CTX_VALID(ctx);
14677 DUK_ASSERT_DISABLE(stridx >= 0);
14678 DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
14679 DUK_ASSERT_DISABLE(builtin_idx >= 0);
14680 DUK_ASSERT(builtin_idx < DUK_NUM_BUILTINS);
14681
14682 obj = duk_require_hobject(ctx, obj_index);
14683 DUK_ASSERT(obj != NULL);
14684 key = DUK_HTHREAD_GET_STRING(thr, stridx);
14685 DUK_ASSERT(key != NULL);
14686
14687 duk_push_hobject(ctx, thr->builtins[builtin_idx]);
14688 duk_hobject_define_property_internal(thr, obj, key, desc_flags);
14689 /* value popped by call */
14690}
14691
14692/* This is a rare property helper; it sets the global thrower (E5 Section 13.2.3)
14693 * setter/getter into an object property. This is needed by the 'arguments'
14694 * object creation code, function instance creation code, and Function.prototype.bind().
14695 */
14696
14697DUK_INTERNAL void duk_xdef_prop_stridx_thrower(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags) {
14698 duk_hthread *thr = (duk_hthread *) ctx;
14699 duk_hobject *obj = duk_require_hobject(ctx, obj_index);
14700 duk_hobject *thrower = thr->builtins[DUK_BIDX_TYPE_ERROR_THROWER];
14701 duk_hobject_define_accessor_internal(thr, obj, DUK_HTHREAD_GET_STRING(thr, stridx), thrower, thrower, desc_flags);
14702}
14703
14704/* Object.defineProperty() equivalent C binding. */
14705DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_index, duk_uint_t flags) {
14706 duk_hthread *thr = (duk_hthread *) ctx;
14707 duk_idx_t idx_base;
14708 duk_hobject *obj;
14709 duk_hstring *key;
14710 duk_idx_t idx_value;
14711 duk_hobject *get;
14712 duk_hobject *set;
14713 duk_uint_t is_data_desc;
14714 duk_uint_t is_acc_desc;
14715
14716 DUK_ASSERT_CTX_VALID(ctx);
14717
14718 obj = duk_require_hobject(ctx, obj_index);
14719
14720 is_data_desc = flags & (DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE);
14721 is_acc_desc = flags & (DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER);
14722 if (is_data_desc && is_acc_desc) {
14723 /* "Have" flags must not be conflicting so that they would
14724 * apply to both a plain property and an accessor at the same
14725 * time.
14726 */
14727 goto fail_invalid_desc;
14728 }
14729
14730 idx_base = duk_get_top_index(ctx);
14731 if (flags & DUK_DEFPROP_HAVE_SETTER) {
14732 duk_require_type_mask(ctx, idx_base, DUK_TYPE_MASK_UNDEFINED |
14733 DUK_TYPE_MASK_OBJECT |
14734 DUK_TYPE_MASK_LIGHTFUNC);
14735 set = duk_get_hobject_or_lfunc_coerce(ctx, idx_base);
14736 if (set != NULL && !DUK_HOBJECT_IS_CALLABLE(set)) {
14737 goto fail_not_callable;
14738 }
14739 idx_base--;
14740 } else {
14741 set = NULL;
14742 }
14743 if (flags & DUK_DEFPROP_HAVE_GETTER) {
14744 duk_require_type_mask(ctx, idx_base, DUK_TYPE_MASK_UNDEFINED |
14745 DUK_TYPE_MASK_OBJECT |
14746 DUK_TYPE_MASK_LIGHTFUNC);
14747 get = duk_get_hobject_or_lfunc_coerce(ctx, idx_base);
14748 if (get != NULL && !DUK_HOBJECT_IS_CALLABLE(get)) {
14749 goto fail_not_callable;
14750 }
14751 idx_base--;
14752 } else {
14753 get = NULL;
14754 }
14755 if (flags & DUK_DEFPROP_HAVE_VALUE) {
14756 idx_value = idx_base;
14757 idx_base--;
14758 } else {
14759 idx_value = (duk_idx_t) -1;
14760 }
14761 key = duk_require_hstring(ctx, idx_base);
14762
14763 duk_require_valid_index(ctx, idx_base);
14764
14765 duk_hobject_define_property_helper(ctx,
14766 flags /*defprop_flags*/,
14767 obj,
14768 key,
14769 idx_value,
14770 get,
14771 set);
14772
14773 /* Clean up stack */
14774
14775 duk_set_top(ctx, idx_base);
14776
14777 /* [ ... obj ... ] */
14778
14779 return;
14780
14781 fail_invalid_desc:
11fdf7f2 14782 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_DESCRIPTOR);
7c673cae
FG
14783 return;
14784
14785 fail_not_callable:
11fdf7f2 14786 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE);
7c673cae
FG
14787 return;
14788}
14789
14790/*
14791 * Object related
14792 *
14793 * Note: seal() and freeze() are accessible through Ecmascript bindings,
14794 * and are not exposed through the API.
14795 */
14796
14797DUK_EXTERNAL void duk_compact(duk_context *ctx, duk_idx_t obj_index) {
14798 duk_hthread *thr = (duk_hthread *) ctx;
14799 duk_hobject *obj;
14800
14801 DUK_ASSERT_CTX_VALID(ctx);
14802
14803 obj = duk_get_hobject(ctx, obj_index);
14804 if (obj) {
14805 /* Note: this may fail, caller should protect the call if necessary */
14806 duk_hobject_compact_props(thr, obj);
14807 }
14808}
14809
14810/* XXX: the duk_hobject_enum.c stack APIs should be reworked */
14811
14812DUK_EXTERNAL void duk_enum(duk_context *ctx, duk_idx_t obj_index, duk_uint_t enum_flags) {
14813 DUK_ASSERT_CTX_VALID(ctx);
14814
14815 duk_dup(ctx, obj_index);
14816 duk_require_hobject_or_lfunc_coerce(ctx, -1);
14817 duk_hobject_enumerator_create(ctx, enum_flags); /* [target] -> [enum] */
14818}
14819
14820DUK_EXTERNAL duk_bool_t duk_next(duk_context *ctx, duk_idx_t enum_index, duk_bool_t get_value) {
14821 DUK_ASSERT_CTX_VALID(ctx);
14822
14823 duk_require_hobject(ctx, enum_index);
14824 duk_dup(ctx, enum_index);
14825 return duk_hobject_enumerator_next(ctx, get_value);
14826}
14827
14828/*
14829 * Helpers for writing multiple properties
14830 */
14831
14832DUK_EXTERNAL void duk_put_function_list(duk_context *ctx, duk_idx_t obj_index, const duk_function_list_entry *funcs) {
14833 const duk_function_list_entry *ent = funcs;
14834
14835 DUK_ASSERT_CTX_VALID(ctx);
14836
14837 obj_index = duk_require_normalize_index(ctx, obj_index);
14838 if (ent != NULL) {
14839 while (ent->key != NULL) {
14840 duk_push_c_function(ctx, ent->value, ent->nargs);
14841 duk_put_prop_string(ctx, obj_index, ent->key);
14842 ent++;
14843 }
14844 }
14845}
14846
14847DUK_EXTERNAL void duk_put_number_list(duk_context *ctx, duk_idx_t obj_index, const duk_number_list_entry *numbers) {
14848 const duk_number_list_entry *ent = numbers;
14849
14850 DUK_ASSERT_CTX_VALID(ctx);
14851
14852 obj_index = duk_require_normalize_index(ctx, obj_index);
14853 if (ent != NULL) {
14854 while (ent->key != NULL) {
14855 duk_push_number(ctx, ent->value);
14856 duk_put_prop_string(ctx, obj_index, ent->key);
14857 ent++;
14858 }
14859 }
14860}
14861
14862/*
14863 * Shortcut for accessing global object properties
14864 */
14865
14866DUK_EXTERNAL duk_bool_t duk_get_global_string(duk_context *ctx, const char *key) {
14867 duk_hthread *thr = (duk_hthread *) ctx;
14868 duk_bool_t ret;
14869
14870 DUK_ASSERT_CTX_VALID(ctx);
14871 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
14872
14873 /* XXX: direct implementation */
14874
14875 duk_push_hobject(ctx, thr->builtins[DUK_BIDX_GLOBAL]);
14876 ret = duk_get_prop_string(ctx, -1, key);
14877 duk_remove(ctx, -2);
14878 return ret;
14879}
14880
14881DUK_EXTERNAL duk_bool_t duk_put_global_string(duk_context *ctx, const char *key) {
14882 duk_hthread *thr = (duk_hthread *) ctx;
14883 duk_bool_t ret;
14884
14885 DUK_ASSERT_CTX_VALID(ctx);
14886 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
14887
14888 /* XXX: direct implementation */
14889
14890 duk_push_hobject(ctx, thr->builtins[DUK_BIDX_GLOBAL]);
14891 duk_insert(ctx, -2);
14892 ret = duk_put_prop_string(ctx, -2, key); /* [ ... global val ] -> [ ... global ] */
14893 duk_pop(ctx);
14894 return ret;
14895}
14896
14897/*
14898 * Object prototype
14899 */
14900
14901DUK_EXTERNAL void duk_get_prototype(duk_context *ctx, duk_idx_t index) {
14902 duk_hthread *thr = (duk_hthread *) ctx;
14903 duk_hobject *obj;
14904 duk_hobject *proto;
14905
14906 DUK_ASSERT_CTX_VALID(ctx);
14907 DUK_UNREF(thr);
14908
14909 obj = duk_require_hobject(ctx, index);
14910 DUK_ASSERT(obj != NULL);
14911
14912 /* XXX: shared helper for duk_push_hobject_or_undefined()? */
14913 proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, obj);
14914 if (proto) {
14915 duk_push_hobject(ctx, proto);
14916 } else {
14917 duk_push_undefined(ctx);
14918 }
14919}
14920
14921DUK_EXTERNAL void duk_set_prototype(duk_context *ctx, duk_idx_t index) {
14922 duk_hthread *thr = (duk_hthread *) ctx;
14923 duk_hobject *obj;
14924 duk_hobject *proto;
14925
14926 DUK_ASSERT_CTX_VALID(ctx);
14927
14928 obj = duk_require_hobject(ctx, index);
14929 DUK_ASSERT(obj != NULL);
14930 duk_require_type_mask(ctx, -1, DUK_TYPE_MASK_UNDEFINED |
14931 DUK_TYPE_MASK_OBJECT);
14932 proto = duk_get_hobject(ctx, -1);
14933 /* proto can also be NULL here (allowed explicitly) */
14934
11fdf7f2
TL
14935#if defined(DUK_USE_ROM_OBJECTS)
14936 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
14937 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE); /* XXX: "read only object"? */
14938 return;
14939 }
14940#endif
14941
7c673cae
FG
14942 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, obj, proto);
14943
14944 duk_pop(ctx);
14945}
14946
14947/*
14948 * Object finalizer
14949 */
14950
14951/* XXX: these could be implemented as macros calling an internal function
14952 * directly.
14953 * XXX: same issue as with Duktape.fin: there's no way to delete the property
14954 * now (just set it to undefined).
14955 */
14956DUK_EXTERNAL void duk_get_finalizer(duk_context *ctx, duk_idx_t index) {
14957 DUK_ASSERT_CTX_VALID(ctx);
14958
14959 duk_get_prop_stridx(ctx, index, DUK_STRIDX_INT_FINALIZER);
14960}
14961
14962DUK_EXTERNAL void duk_set_finalizer(duk_context *ctx, duk_idx_t index) {
14963 DUK_ASSERT_CTX_VALID(ctx);
14964
14965 duk_put_prop_stridx(ctx, index, DUK_STRIDX_INT_FINALIZER);
14966}
7c673cae
FG
14967/*
14968 * API calls related to general value stack manipulation: resizing the value
14969 * stack, pushing and popping values, type checking and reading values,
14970 * coercing values, etc.
14971 *
14972 * Also contains internal functions (such as duk_get_tval()), defined
14973 * in duk_api_internal.h, with semantics similar to the public API.
14974 */
14975
14976/* XXX: repetition of stack pre-checks -> helper or macro or inline */
14977/* XXX: shared api error strings, and perhaps even throw code for rare cases? */
14978
14979/* include removed: duk_internal.h */
14980
14981/*
14982 * Forward declarations
14983 */
14984
14985DUK_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);
14986
14987/*
14988 * Global state for working around missing variadic macros
14989 */
14990
14991#ifndef DUK_USE_VARIADIC_MACROS
14992DUK_EXTERNAL const char *duk_api_global_filename = NULL;
14993DUK_EXTERNAL duk_int_t duk_api_global_line = 0;
14994#endif
14995
14996/*
11fdf7f2 14997 * Misc helpers
7c673cae
FG
14998 */
14999
11fdf7f2 15000/* Check that there's room to push one value. */
7c673cae
FG
15001#if defined(DUK_USE_VALSTACK_UNSAFE)
15002/* Faster but value stack overruns are memory unsafe. */
11fdf7f2 15003#define DUK__CHECK_SPACE() do { \
7c673cae
FG
15004 DUK_ASSERT(!(thr->valstack_top >= thr->valstack_end)); \
15005 } while (0)
15006#else
11fdf7f2
TL
15007#define DUK__CHECK_SPACE() do { \
15008 if (DUK_UNLIKELY(thr->valstack_top >= thr->valstack_end)) { \
15009 DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); \
7c673cae
FG
15010 } \
15011 } while (0)
15012#endif
15013
11fdf7f2
TL
15014DUK_LOCAL_DECL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t index, duk_uint_t tag);
15015
7c673cae
FG
15016DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t index, duk_bool_t require) {
15017 duk_hthread *thr;
15018 duk_tval *tv;
15019 duk_small_int_t c;
15020 duk_double_t d;
15021
15022 thr = (duk_hthread *) ctx;
15023
15024 tv = duk_get_tval(ctx, index);
15025 if (tv == NULL) {
15026 goto error_notnumber;
15027 }
15028
15029 /*
15030 * Special cases like NaN and +/- Infinity are handled explicitly
15031 * because a plain C coercion from double to int handles these cases
15032 * in undesirable ways. For instance, NaN may coerce to INT_MIN
15033 * (not zero), and INT_MAX + 1 may coerce to INT_MIN (not INT_MAX).
15034 *
15035 * This double-to-int coercion differs from ToInteger() because it
15036 * has a finite range (ToInteger() allows e.g. +/- Infinity). It
15037 * also differs from ToInt32() because the INT_MIN/INT_MAX clamping
15038 * depends on the size of the int type on the platform. In particular,
15039 * on platforms with a 64-bit int type, the full range is allowed.
15040 */
15041
15042#if defined(DUK_USE_FASTINT)
15043 if (DUK_TVAL_IS_FASTINT(tv)) {
15044 duk_int64_t t = DUK_TVAL_GET_FASTINT(tv);
15045#if (DUK_INT_MAX <= 0x7fffffffL)
15046 /* Clamping only necessary for 32-bit ints. */
15047 if (t < DUK_INT_MIN) {
15048 t = DUK_INT_MIN;
15049 } else if (t > DUK_INT_MAX) {
15050 t = DUK_INT_MAX;
15051 }
15052#endif
15053 return (duk_int_t) t;
15054 }
15055#endif
15056
15057 if (DUK_TVAL_IS_NUMBER(tv)) {
15058 d = DUK_TVAL_GET_NUMBER(tv);
15059 c = (duk_small_int_t) DUK_FPCLASSIFY(d);
15060 if (c == DUK_FP_NAN) {
15061 return 0;
15062 } else if (d < (duk_double_t) DUK_INT_MIN) {
15063 /* covers -Infinity */
15064 return DUK_INT_MIN;
15065 } else if (d > (duk_double_t) DUK_INT_MAX) {
15066 /* covers +Infinity */
15067 return DUK_INT_MAX;
15068 } else {
15069 /* coerce towards zero */
15070 return (duk_int_t) d;
15071 }
15072 }
15073
15074 error_notnumber:
15075
15076 if (require) {
11fdf7f2 15077 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "number", DUK_STR_NOT_NUMBER);
7c673cae
FG
15078 /* not reachable */
15079 }
15080 return 0;
15081}
15082
15083DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t index, duk_bool_t require) {
15084 duk_hthread *thr;
15085 duk_tval *tv;
15086 duk_small_int_t c;
15087 duk_double_t d;
15088
15089 /* Same as above but for unsigned int range. */
15090
15091 thr = (duk_hthread *) ctx;
15092
15093 tv = duk_get_tval(ctx, index);
15094 if (tv == NULL) {
15095 goto error_notnumber;
15096 }
15097
15098#if defined(DUK_USE_FASTINT)
15099 if (DUK_TVAL_IS_FASTINT(tv)) {
15100 duk_int64_t t = DUK_TVAL_GET_FASTINT(tv);
15101 if (t < 0) {
15102 t = 0;
15103 }
15104#if (DUK_UINT_MAX <= 0xffffffffUL)
15105 /* Clamping only necessary for 32-bit ints. */
15106 else if (t > DUK_UINT_MAX) {
15107 t = DUK_UINT_MAX;
15108 }
15109#endif
15110 return (duk_uint_t) t;
15111 }
15112#endif
15113
15114 if (DUK_TVAL_IS_NUMBER(tv)) {
15115 d = DUK_TVAL_GET_NUMBER(tv);
15116 c = (duk_small_int_t) DUK_FPCLASSIFY(d);
15117 if (c == DUK_FP_NAN) {
15118 return 0;
15119 } else if (d < 0.0) {
15120 /* covers -Infinity */
15121 return (duk_uint_t) 0;
15122 } else if (d > (duk_double_t) DUK_UINT_MAX) {
15123 /* covers +Infinity */
15124 return (duk_uint_t) DUK_UINT_MAX;
15125 } else {
15126 /* coerce towards zero */
15127 return (duk_uint_t) d;
15128 }
15129 }
15130
15131 error_notnumber:
15132
15133 if (require) {
11fdf7f2 15134 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "number", DUK_STR_NOT_NUMBER);
7c673cae
FG
15135 /* not reachable */
15136 }
15137 return 0;
15138}
15139
15140/*
15141 * Stack index validation/normalization and getting a stack duk_tval ptr.
15142 *
15143 * These are called by many API entrypoints so the implementations must be
15144 * fast and "inlined".
15145 *
15146 * There's some repetition because of this; keep the functions in sync.
15147 */
15148
15149DUK_EXTERNAL duk_idx_t duk_normalize_index(duk_context *ctx, duk_idx_t index) {
15150 duk_hthread *thr = (duk_hthread *) ctx;
11fdf7f2
TL
15151 duk_uidx_t vs_size;
15152 duk_uidx_t uindex;
7c673cae
FG
15153
15154 DUK_ASSERT_CTX_VALID(ctx);
15155 DUK_ASSERT(DUK_INVALID_INDEX < 0);
15156
15157 /* Care must be taken to avoid pointer wrapping in the index
15158 * validation. For instance, on a 32-bit platform with 8-byte
15159 * duk_tval the index 0x20000000UL would wrap the memory space
15160 * once.
15161 */
15162
15163 /* Assume value stack sizes (in elements) fits into duk_idx_t. */
11fdf7f2
TL
15164 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
15165 vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
15166 DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */
7c673cae
FG
15167
15168 if (index < 0) {
11fdf7f2 15169 uindex = vs_size + (duk_uidx_t) index;
7c673cae
FG
15170 } else {
15171 /* since index non-negative */
15172 DUK_ASSERT(index != DUK_INVALID_INDEX);
11fdf7f2 15173 uindex = (duk_uidx_t) index;
7c673cae
FG
15174 }
15175
11fdf7f2
TL
15176 /* DUK_INVALID_INDEX won't be accepted as a valid index. */
15177 DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
15178
15179 if (DUK_LIKELY(uindex < vs_size)) {
15180 return (duk_idx_t) uindex;
15181 }
15182 return DUK_INVALID_INDEX;
7c673cae
FG
15183}
15184
15185DUK_EXTERNAL duk_idx_t duk_require_normalize_index(duk_context *ctx, duk_idx_t index) {
15186 duk_hthread *thr = (duk_hthread *) ctx;
11fdf7f2
TL
15187 duk_uidx_t vs_size;
15188 duk_uidx_t uindex;
7c673cae
FG
15189
15190 DUK_ASSERT_CTX_VALID(ctx);
15191 DUK_ASSERT(DUK_INVALID_INDEX < 0);
15192
11fdf7f2
TL
15193 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
15194 vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
15195 DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */
7c673cae
FG
15196
15197 if (index < 0) {
11fdf7f2 15198 uindex = vs_size + (duk_uidx_t) index;
7c673cae
FG
15199 } else {
15200 DUK_ASSERT(index != DUK_INVALID_INDEX);
11fdf7f2 15201 uindex = (duk_uidx_t) index;
7c673cae
FG
15202 }
15203
11fdf7f2
TL
15204 /* DUK_INVALID_INDEX won't be accepted as a valid index. */
15205 DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
7c673cae 15206
11fdf7f2
TL
15207 if (DUK_LIKELY(uindex < vs_size)) {
15208 return (duk_idx_t) uindex;
15209 }
15210 DUK_ERROR_API_INDEX(thr, index);
7c673cae
FG
15211 return 0; /* unreachable */
15212}
15213
15214DUK_INTERNAL duk_tval *duk_get_tval(duk_context *ctx, duk_idx_t index) {
15215 duk_hthread *thr = (duk_hthread *) ctx;
11fdf7f2
TL
15216 duk_uidx_t vs_size;
15217 duk_uidx_t uindex;
7c673cae
FG
15218
15219 DUK_ASSERT_CTX_VALID(ctx);
15220 DUK_ASSERT(DUK_INVALID_INDEX < 0);
15221
11fdf7f2
TL
15222 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
15223 vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
15224 DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */
7c673cae
FG
15225
15226 if (index < 0) {
11fdf7f2 15227 uindex = vs_size + (duk_uidx_t) index;
7c673cae
FG
15228 } else {
15229 DUK_ASSERT(index != DUK_INVALID_INDEX);
11fdf7f2 15230 uindex = (duk_uidx_t) index;
7c673cae
FG
15231 }
15232
11fdf7f2
TL
15233 /* DUK_INVALID_INDEX won't be accepted as a valid index. */
15234 DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
15235
15236 if (DUK_LIKELY(uindex < vs_size)) {
15237 return thr->valstack_bottom + uindex;
15238 }
15239 return NULL;
7c673cae
FG
15240}
15241
15242DUK_INTERNAL duk_tval *duk_require_tval(duk_context *ctx, duk_idx_t index) {
15243 duk_hthread *thr = (duk_hthread *) ctx;
11fdf7f2
TL
15244 duk_uidx_t vs_size;
15245 duk_uidx_t uindex;
7c673cae
FG
15246
15247 DUK_ASSERT_CTX_VALID(ctx);
15248 DUK_ASSERT(DUK_INVALID_INDEX < 0);
15249
11fdf7f2
TL
15250 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
15251 vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
15252 DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */
7c673cae 15253
11fdf7f2 15254 /* Use unsigned arithmetic to optimize comparison. */
7c673cae 15255 if (index < 0) {
11fdf7f2 15256 uindex = vs_size + (duk_uidx_t) index;
7c673cae
FG
15257 } else {
15258 DUK_ASSERT(index != DUK_INVALID_INDEX);
11fdf7f2 15259 uindex = (duk_uidx_t) index;
7c673cae
FG
15260 }
15261
11fdf7f2
TL
15262 /* DUK_INVALID_INDEX won't be accepted as a valid index. */
15263 DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
7c673cae 15264
11fdf7f2
TL
15265 if (DUK_LIKELY(uindex < vs_size)) {
15266 return thr->valstack_bottom + uindex;
15267 }
15268 DUK_ERROR_API_INDEX(thr, index);
7c673cae
FG
15269 return NULL;
15270}
15271
15272/* Non-critical. */
15273DUK_EXTERNAL duk_bool_t duk_is_valid_index(duk_context *ctx, duk_idx_t index) {
15274 DUK_ASSERT_CTX_VALID(ctx);
15275 DUK_ASSERT(DUK_INVALID_INDEX < 0);
15276
15277 return (duk_normalize_index(ctx, index) >= 0);
15278}
15279
15280/* Non-critical. */
15281DUK_EXTERNAL void duk_require_valid_index(duk_context *ctx, duk_idx_t index) {
15282 duk_hthread *thr = (duk_hthread *) ctx;
15283
15284 DUK_ASSERT_CTX_VALID(ctx);
15285 DUK_ASSERT(DUK_INVALID_INDEX < 0);
15286
15287 if (duk_normalize_index(ctx, index) < 0) {
11fdf7f2
TL
15288 DUK_ERROR_API_INDEX(thr, index);
15289 return; /* unreachable */
7c673cae
FG
15290 }
15291}
15292
15293/*
15294 * Value stack top handling
15295 */
15296
15297DUK_EXTERNAL duk_idx_t duk_get_top(duk_context *ctx) {
15298 duk_hthread *thr = (duk_hthread *) ctx;
15299
15300 DUK_ASSERT_CTX_VALID(ctx);
15301
15302 return (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
15303}
15304
11fdf7f2
TL
15305/* Set stack top within currently allocated range, but don't reallocate.
15306 * This is performance critical especially for call handling, so whenever
15307 * changing, profile and look at generated code.
15308 */
7c673cae
FG
15309DUK_EXTERNAL void duk_set_top(duk_context *ctx, duk_idx_t index) {
15310 duk_hthread *thr = (duk_hthread *) ctx;
11fdf7f2
TL
15311 duk_uidx_t vs_size;
15312 duk_uidx_t vs_limit;
15313 duk_uidx_t uindex;
7c673cae
FG
15314 duk_tval *tv;
15315
15316 DUK_ASSERT_CTX_VALID(ctx);
15317 DUK_ASSERT(DUK_INVALID_INDEX < 0);
15318
11fdf7f2
TL
15319 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
15320 DUK_ASSERT(thr->valstack_end >= thr->valstack_bottom);
15321 vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
15322 vs_limit = (duk_uidx_t) (thr->valstack_end - thr->valstack_bottom);
7c673cae
FG
15323
15324 if (index < 0) {
15325 /* Negative indices are always within allocated stack but
15326 * must not go below zero index.
15327 */
11fdf7f2 15328 uindex = vs_size + (duk_uidx_t) index;
7c673cae
FG
15329 } else {
15330 /* Positive index can be higher than valstack top but must
15331 * not go above allocated stack (equality is OK).
15332 */
11fdf7f2 15333 uindex = (duk_uidx_t) index;
7c673cae 15334 }
7c673cae 15335
11fdf7f2
TL
15336 /* DUK_INVALID_INDEX won't be accepted as a valid index. */
15337 DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
15338 DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_limit);
7c673cae 15339
11fdf7f2
TL
15340#if defined(DUK_USE_VALSTACK_UNSAFE)
15341 DUK_ASSERT(uindex <= vs_limit);
15342 DUK_UNREF(vs_limit);
15343#else
15344 if (DUK_UNLIKELY(uindex > vs_limit)) {
15345 DUK_ERROR_API_INDEX(thr, index);
15346 return; /* unreachable */
15347 }
15348#endif
15349 DUK_ASSERT(uindex <= vs_limit);
15350
15351 /* Handle change in value stack top. Respect value stack
15352 * initialization policy: 'undefined' above top. Note that
15353 * DECREF may cause a side effect that reallocates valstack,
15354 * so must relookup after DECREF.
15355 */
15356
15357 if (uindex >= vs_size) {
15358 /* Stack size increases or stays the same. */
15359#if defined(DUK_USE_ASSERTIONS)
15360 duk_uidx_t count;
15361
15362 count = uindex - vs_size;
15363 while (count != 0) {
7c673cae 15364 count--;
11fdf7f2
TL
15365 tv = thr->valstack_top + count;
15366 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv));
7c673cae 15367 }
11fdf7f2
TL
15368#endif
15369 thr->valstack_top = thr->valstack_bottom + uindex;
7c673cae 15370 } else {
11fdf7f2
TL
15371 /* Stack size decreases. */
15372#if defined(DUK_USE_REFERENCE_COUNTING)
15373 duk_uidx_t count;
7c673cae 15374
11fdf7f2 15375 count = vs_size - uindex;
7c673cae 15376 DUK_ASSERT(count > 0);
7c673cae
FG
15377 while (count > 0) {
15378 count--;
11fdf7f2 15379 tv = --thr->valstack_top; /* tv -> value just before prev top value; must relookup */
7c673cae 15380 DUK_ASSERT(tv >= thr->valstack_bottom);
11fdf7f2 15381 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
7c673cae 15382 }
11fdf7f2
TL
15383#else /* DUK_USE_REFERENCE_COUNTING */
15384 duk_uidx_t count;
15385 duk_tval *tv_end;
7c673cae 15386
11fdf7f2
TL
15387 count = vs_size - uindex;
15388 tv = thr->valstack_top;
15389 tv_end = tv - count;
15390 DUK_ASSERT(tv > tv_end);
15391 do {
15392 tv--;
15393 DUK_TVAL_SET_UNDEFINED(tv);
15394 } while (tv != tv_end);
15395 thr->valstack_top = tv_end;
15396#endif /* DUK_USE_REFERENCE_COUNTING */
15397 }
7c673cae
FG
15398}
15399
15400DUK_EXTERNAL duk_idx_t duk_get_top_index(duk_context *ctx) {
15401 duk_hthread *thr = (duk_hthread *) ctx;
15402 duk_idx_t ret;
15403
15404 DUK_ASSERT_CTX_VALID(ctx);
15405
15406 ret = ((duk_idx_t) (thr->valstack_top - thr->valstack_bottom)) - 1;
15407 if (DUK_UNLIKELY(ret < 0)) {
15408 /* Return invalid index; if caller uses this without checking
15409 * in another API call, the index won't map to a valid stack
15410 * entry.
15411 */
15412 return DUK_INVALID_INDEX;
15413 }
15414 return ret;
15415}
15416
15417DUK_EXTERNAL duk_idx_t duk_require_top_index(duk_context *ctx) {
15418 duk_hthread *thr = (duk_hthread *) ctx;
15419 duk_idx_t ret;
15420
15421 DUK_ASSERT_CTX_VALID(ctx);
15422
15423 ret = ((duk_idx_t) (thr->valstack_top - thr->valstack_bottom)) - 1;
15424 if (DUK_UNLIKELY(ret < 0)) {
11fdf7f2
TL
15425 DUK_ERROR_API_INDEX(thr, -1);
15426 return 0; /* unreachable */
7c673cae
FG
15427 }
15428 return ret;
15429}
15430
15431/*
15432 * Value stack resizing.
15433 *
15434 * This resizing happens above the current "top": the value stack can be
15435 * grown or shrunk, but the "top" is not affected. The value stack cannot
15436 * be resized to a size below the current "top".
15437 *
15438 * The low level reallocation primitive must carefully recompute all value
15439 * stack pointers, and must also work if ALL pointers are NULL. The resize
15440 * is quite tricky because the valstack realloc may cause a mark-and-sweep,
15441 * which may run finalizers. Running finalizers may resize the valstack
15442 * recursively (the same value stack we're working on). So, after realloc
15443 * returns, we know that the valstack "top" should still be the same (there
15444 * should not be live values above the "top"), but its underlying size and
15445 * pointer may have changed.
15446 */
15447
15448/* XXX: perhaps refactor this to allow caller to specify some parameters, or
15449 * at least a 'compact' flag which skips any spare or round-up .. useful for
15450 * emergency gc.
15451 */
15452
15453DUK_LOCAL duk_bool_t duk__resize_valstack(duk_context *ctx, duk_size_t new_size) {
15454 duk_hthread *thr = (duk_hthread *) ctx;
15455 duk_ptrdiff_t old_bottom_offset;
15456 duk_ptrdiff_t old_top_offset;
15457 duk_ptrdiff_t old_end_offset_post;
15458#ifdef DUK_USE_DEBUG
15459 duk_ptrdiff_t old_end_offset_pre;
15460 duk_tval *old_valstack_pre;
15461 duk_tval *old_valstack_post;
15462#endif
15463 duk_tval *new_valstack;
7c673cae 15464 duk_size_t new_alloc_size;
11fdf7f2 15465 duk_tval *p;
7c673cae
FG
15466
15467 DUK_ASSERT_CTX_VALID(ctx);
15468 DUK_ASSERT(thr != NULL);
15469 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
15470 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
15471 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
15472 DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack) <= new_size); /* can't resize below 'top' */
15473 DUK_ASSERT(new_size <= thr->valstack_max); /* valstack limit caller has check, prevents wrapping */
15474 DUK_ASSERT(new_size <= DUK_SIZE_MAX / sizeof(duk_tval)); /* specific assert for wrapping */
15475
15476 /* get pointer offsets for tweaking below */
15477 old_bottom_offset = (((duk_uint8_t *) thr->valstack_bottom) - ((duk_uint8_t *) thr->valstack));
15478 old_top_offset = (((duk_uint8_t *) thr->valstack_top) - ((duk_uint8_t *) thr->valstack));
15479#ifdef DUK_USE_DEBUG
15480 old_end_offset_pre = (((duk_uint8_t *) thr->valstack_end) - ((duk_uint8_t *) thr->valstack)); /* not very useful, used for debugging */
15481 old_valstack_pre = thr->valstack;
15482#endif
15483
15484 /* Allocate a new valstack.
15485 *
15486 * Note: cannot use a plain DUK_REALLOC() because a mark-and-sweep may
15487 * invalidate the original thr->valstack base pointer inside the realloc
15488 * process. See doc/memory-management.rst.
15489 */
15490
15491 new_alloc_size = sizeof(duk_tval) * new_size;
15492 new_valstack = (duk_tval *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_valstack_ptr, (void *) thr, new_alloc_size);
15493 if (!new_valstack) {
15494 /* Because new_size != 0, if condition doesn't need to be
15495 * (new_valstack != NULL || new_size == 0).
15496 */
15497 DUK_ASSERT(new_size != 0);
15498 DUK_D(DUK_DPRINT("failed to resize valstack to %lu entries (%lu bytes)",
15499 (unsigned long) new_size, (unsigned long) new_alloc_size));
15500 return 0;
15501 }
15502
15503 /* Note: the realloc may have triggered a mark-and-sweep which may
15504 * have resized our valstack internally. However, the mark-and-sweep
15505 * MUST NOT leave the stack bottom/top in a different state. Particular
15506 * assumptions and facts:
15507 *
15508 * - The thr->valstack pointer may be different after realloc,
15509 * and the offset between thr->valstack_end <-> thr->valstack
15510 * may have changed.
15511 * - The offset between thr->valstack_bottom <-> thr->valstack
15512 * and thr->valstack_top <-> thr->valstack MUST NOT have changed,
15513 * because mark-and-sweep must adhere to a strict stack policy.
15514 * In other words, logical bottom and top MUST NOT have changed.
15515 * - All values above the top are unreachable but are initialized
11fdf7f2 15516 * to UNDEFINED, up to the post-realloc valstack_end.
7c673cae
FG
15517 * - 'old_end_offset' must be computed after realloc to be correct.
15518 */
15519
15520 DUK_ASSERT((((duk_uint8_t *) thr->valstack_bottom) - ((duk_uint8_t *) thr->valstack)) == old_bottom_offset);
15521 DUK_ASSERT((((duk_uint8_t *) thr->valstack_top) - ((duk_uint8_t *) thr->valstack)) == old_top_offset);
15522
15523 /* success, fixup pointers */
15524 old_end_offset_post = (((duk_uint8_t *) thr->valstack_end) - ((duk_uint8_t *) thr->valstack)); /* must be computed after realloc */
15525#ifdef DUK_USE_DEBUG
15526 old_valstack_post = thr->valstack;
15527#endif
15528 thr->valstack = new_valstack;
15529 thr->valstack_end = new_valstack + new_size;
11fdf7f2
TL
15530#if !defined(DUK_USE_PREFER_SIZE)
15531 thr->valstack_size = new_size;
15532#endif
7c673cae
FG
15533 thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) new_valstack + old_bottom_offset);
15534 thr->valstack_top = (duk_tval *) (void *) ((duk_uint8_t *) new_valstack + old_top_offset);
15535
15536 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
15537 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
15538 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
15539
15540 /* useful for debugging */
15541#ifdef DUK_USE_DEBUG
15542 if (old_end_offset_pre != old_end_offset_post) {
15543 DUK_D(DUK_DPRINT("valstack was resized during valstack_resize(), probably by mark-and-sweep; "
15544 "end offset changed: %lu -> %lu",
15545 (unsigned long) old_end_offset_pre,
15546 (unsigned long) old_end_offset_post));
15547 }
15548 if (old_valstack_pre != old_valstack_post) {
15549 DUK_D(DUK_DPRINT("valstack pointer changed during valstack_resize(), probably by mark-and-sweep: %p -> %p",
15550 (void *) old_valstack_pre,
15551 (void *) old_valstack_post));
15552 }
15553#endif
15554
15555 DUK_DD(DUK_DDPRINT("resized valstack to %lu elements (%lu bytes), bottom=%ld, top=%ld, "
15556 "new pointers: start=%p end=%p bottom=%p top=%p",
15557 (unsigned long) new_size, (unsigned long) new_alloc_size,
15558 (long) (thr->valstack_bottom - thr->valstack),
15559 (long) (thr->valstack_top - thr->valstack),
15560 (void *) thr->valstack, (void *) thr->valstack_end,
15561 (void *) thr->valstack_bottom, (void *) thr->valstack_top));
15562
11fdf7f2 15563 /* Init newly allocated slots (only). */
7c673cae
FG
15564 p = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + old_end_offset_post);
15565 while (p < thr->valstack_end) {
11fdf7f2
TL
15566 /* Never executed if new size is smaller. */
15567 DUK_TVAL_SET_UNDEFINED(p);
7c673cae
FG
15568 p++;
15569 }
15570
11fdf7f2
TL
15571 /* Assert for value stack initialization policy. */
15572#if defined(DUK_USE_ASSERTIONS)
7c673cae
FG
15573 p = thr->valstack_top;
15574 while (p < thr->valstack_end) {
11fdf7f2 15575 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(p));
7c673cae
FG
15576 p++;
15577 }
15578#endif
11fdf7f2 15579
7c673cae
FG
15580 return 1;
15581}
15582
15583DUK_INTERNAL
15584duk_bool_t duk_valstack_resize_raw(duk_context *ctx,
15585 duk_size_t min_new_size,
15586 duk_small_uint_t flags) {
15587 duk_hthread *thr = (duk_hthread *) ctx;
15588 duk_size_t old_size;
15589 duk_size_t new_size;
15590 duk_bool_t is_shrink = 0;
15591 duk_small_uint_t shrink_flag = (flags & DUK_VSRESIZE_FLAG_SHRINK);
15592 duk_small_uint_t compact_flag = (flags & DUK_VSRESIZE_FLAG_COMPACT);
15593 duk_small_uint_t throw_flag = (flags & DUK_VSRESIZE_FLAG_THROW);
15594
15595 DUK_DDD(DUK_DDDPRINT("check valstack resize: min_new_size=%lu, curr_size=%ld, curr_top=%ld, "
15596 "curr_bottom=%ld, shrink=%d, compact=%d, throw=%d",
15597 (unsigned long) min_new_size,
15598 (long) (thr->valstack_end - thr->valstack),
15599 (long) (thr->valstack_top - thr->valstack),
15600 (long) (thr->valstack_bottom - thr->valstack),
15601 (int) shrink_flag, (int) compact_flag, (int) throw_flag));
15602
15603 DUK_ASSERT_CTX_VALID(ctx);
15604 DUK_ASSERT(thr != NULL);
15605 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
15606 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
15607 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
15608
11fdf7f2 15609#if defined(DUK_USE_PREFER_SIZE)
7c673cae 15610 old_size = (duk_size_t) (thr->valstack_end - thr->valstack);
11fdf7f2
TL
15611#else
15612 DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack) == thr->valstack_size);
15613 old_size = thr->valstack_size;
15614#endif
7c673cae
FG
15615
15616 if (min_new_size <= old_size) {
15617 is_shrink = 1;
15618 if (!shrink_flag ||
15619 old_size - min_new_size < DUK_VALSTACK_SHRINK_THRESHOLD) {
15620 DUK_DDD(DUK_DDDPRINT("no need to grow or shrink valstack"));
15621 return 1;
15622 }
15623 }
15624
15625 new_size = min_new_size;
15626 if (!compact_flag) {
15627 if (is_shrink) {
15628 /* shrink case; leave some spare */
15629 new_size += DUK_VALSTACK_SHRINK_SPARE;
15630 }
15631
15632 /* round up roughly to next 'grow step' */
15633 new_size = (new_size / DUK_VALSTACK_GROW_STEP + 1) * DUK_VALSTACK_GROW_STEP;
15634 }
15635
15636 DUK_DD(DUK_DDPRINT("want to %s valstack: %lu -> %lu elements (min_new_size %lu)",
15637 (const char *) (new_size > old_size ? "grow" : "shrink"),
15638 (unsigned long) old_size, (unsigned long) new_size,
15639 (unsigned long) min_new_size));
15640
15641 if (new_size > thr->valstack_max) {
15642 /* Note: may be triggered even if minimal new_size would not reach the limit,
15643 * plan limit accordingly (taking DUK_VALSTACK_GROW_STEP into account).
15644 */
15645 if (throw_flag) {
11fdf7f2 15646 DUK_ERROR_RANGE(thr, DUK_STR_VALSTACK_LIMIT);
7c673cae
FG
15647 } else {
15648 return 0;
15649 }
15650 }
15651
15652 /*
15653 * When resizing the valstack, a mark-and-sweep may be triggered for
15654 * the allocation of the new valstack. If the mark-and-sweep needs
15655 * to use our thread for something, it may cause *the same valstack*
15656 * to be resized recursively. This happens e.g. when mark-and-sweep
15657 * finalizers are called. This is taken into account carefully in
15658 * duk__resize_valstack().
15659 *
15660 * 'new_size' is known to be <= valstack_max, which ensures that
15661 * size_t and pointer arithmetic won't wrap in duk__resize_valstack().
15662 */
15663
15664 if (!duk__resize_valstack(ctx, new_size)) {
15665 if (is_shrink) {
15666 DUK_DD(DUK_DDPRINT("valstack resize failed, but is a shrink, ignore"));
15667 return 1;
15668 }
15669
15670 DUK_DD(DUK_DDPRINT("valstack resize failed"));
15671
15672 if (throw_flag) {
11fdf7f2 15673 DUK_ERROR_ALLOC_DEFMSG(thr);
7c673cae
FG
15674 } else {
15675 return 0;
15676 }
15677 }
15678
15679 DUK_DDD(DUK_DDDPRINT("valstack resize successful"));
15680 return 1;
15681}
15682
15683DUK_EXTERNAL duk_bool_t duk_check_stack(duk_context *ctx, duk_idx_t extra) {
15684 duk_hthread *thr = (duk_hthread *) ctx;
15685 duk_size_t min_new_size;
15686
15687 DUK_ASSERT_CTX_VALID(ctx);
15688 DUK_ASSERT(thr != NULL);
15689
15690 if (DUK_UNLIKELY(extra < 0)) {
15691 /* Clamping to zero makes the API more robust to calling code
15692 * calculation errors.
15693 */
15694 extra = 0;
15695 }
15696
15697 min_new_size = (thr->valstack_top - thr->valstack) + extra + DUK_VALSTACK_INTERNAL_EXTRA;
15698 return duk_valstack_resize_raw(ctx,
15699 min_new_size, /* min_new_size */
15700 0 /* no shrink */ | /* flags */
15701 0 /* no compact */ |
15702 0 /* no throw */);
15703}
15704
15705DUK_EXTERNAL void duk_require_stack(duk_context *ctx, duk_idx_t extra) {
15706 duk_hthread *thr = (duk_hthread *) ctx;
15707 duk_size_t min_new_size;
15708
15709 DUK_ASSERT_CTX_VALID(ctx);
15710 DUK_ASSERT(thr != NULL);
15711
15712 if (DUK_UNLIKELY(extra < 0)) {
15713 /* Clamping to zero makes the API more robust to calling code
15714 * calculation errors.
15715 */
15716 extra = 0;
15717 }
15718
15719 min_new_size = (thr->valstack_top - thr->valstack) + extra + DUK_VALSTACK_INTERNAL_EXTRA;
15720 (void) duk_valstack_resize_raw(ctx,
15721 min_new_size, /* min_new_size */
15722 0 /* no shrink */ | /* flags */
15723 0 /* no compact */ |
15724 DUK_VSRESIZE_FLAG_THROW);
15725}
15726
15727DUK_EXTERNAL duk_bool_t duk_check_stack_top(duk_context *ctx, duk_idx_t top) {
11fdf7f2 15728 duk_hthread *thr;
7c673cae
FG
15729 duk_size_t min_new_size;
15730
15731 DUK_ASSERT_CTX_VALID(ctx);
11fdf7f2 15732 thr = (duk_hthread *) ctx;
7c673cae
FG
15733
15734 if (DUK_UNLIKELY(top < 0)) {
15735 /* Clamping to zero makes the API more robust to calling code
15736 * calculation errors.
15737 */
15738 top = 0;
15739 }
15740
11fdf7f2 15741 min_new_size = (thr->valstack_bottom - thr->valstack) + top + DUK_VALSTACK_INTERNAL_EXTRA;
7c673cae
FG
15742 return duk_valstack_resize_raw(ctx,
15743 min_new_size, /* min_new_size */
15744 0 /* no shrink */ | /* flags */
15745 0 /* no compact */ |
15746 0 /* no throw */);
15747}
15748
15749DUK_EXTERNAL void duk_require_stack_top(duk_context *ctx, duk_idx_t top) {
11fdf7f2 15750 duk_hthread *thr;
7c673cae
FG
15751 duk_size_t min_new_size;
15752
15753 DUK_ASSERT_CTX_VALID(ctx);
11fdf7f2 15754 thr = (duk_hthread *) ctx;
7c673cae
FG
15755
15756 if (DUK_UNLIKELY(top < 0)) {
15757 /* Clamping to zero makes the API more robust to calling code
15758 * calculation errors.
15759 */
15760 top = 0;
15761 }
15762
11fdf7f2 15763 min_new_size = (thr->valstack_bottom - thr->valstack) + top + DUK_VALSTACK_INTERNAL_EXTRA;
7c673cae
FG
15764 (void) duk_valstack_resize_raw(ctx,
15765 min_new_size, /* min_new_size */
15766 0 /* no shrink */ | /* flags */
15767 0 /* no compact */ |
15768 DUK_VSRESIZE_FLAG_THROW);
15769}
15770
15771/*
15772 * Basic stack manipulation: swap, dup, insert, replace, etc
15773 */
15774
15775DUK_EXTERNAL void duk_swap(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) {
15776 duk_tval *tv1;
15777 duk_tval *tv2;
15778 duk_tval tv_tmp;
15779
15780 DUK_ASSERT_CTX_VALID(ctx);
15781
15782 tv1 = duk_require_tval(ctx, index1);
15783 DUK_ASSERT(tv1 != NULL);
15784 tv2 = duk_require_tval(ctx, index2);
15785 DUK_ASSERT(tv2 != NULL);
15786
15787 /* If tv1==tv2 this is a NOP, no check is needed */
15788 DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
15789 DUK_TVAL_SET_TVAL(tv1, tv2);
15790 DUK_TVAL_SET_TVAL(tv2, &tv_tmp);
15791}
15792
15793DUK_EXTERNAL void duk_swap_top(duk_context *ctx, duk_idx_t index) {
15794 DUK_ASSERT_CTX_VALID(ctx);
15795
15796 duk_swap(ctx, index, -1);
15797}
15798
15799DUK_EXTERNAL void duk_dup(duk_context *ctx, duk_idx_t from_index) {
15800 duk_hthread *thr;
15801 duk_tval *tv_from;
15802 duk_tval *tv_to;
15803
15804 DUK_ASSERT_CTX_VALID(ctx);
15805 thr = (duk_hthread *) ctx;
15806 DUK__CHECK_SPACE();
15807
15808 tv_from = duk_require_tval(ctx, from_index);
15809 tv_to = thr->valstack_top++;
15810 DUK_ASSERT(tv_from != NULL);
15811 DUK_ASSERT(tv_to != NULL);
15812 DUK_TVAL_SET_TVAL(tv_to, tv_from);
15813 DUK_TVAL_INCREF(thr, tv_to); /* no side effects */
15814}
15815
15816DUK_EXTERNAL void duk_dup_top(duk_context *ctx) {
15817 duk_hthread *thr;
15818 duk_tval *tv_from;
15819 duk_tval *tv_to;
15820
15821 DUK_ASSERT_CTX_VALID(ctx);
15822 thr = (duk_hthread *) ctx;
15823 DUK__CHECK_SPACE();
15824
15825 if (thr->valstack_top - thr->valstack_bottom <= 0) {
11fdf7f2
TL
15826 DUK_ERROR_API_INDEX(thr, -1);
15827 return; /* unreachable */
7c673cae
FG
15828 }
15829 tv_from = thr->valstack_top - 1;
15830 tv_to = thr->valstack_top++;
15831 DUK_ASSERT(tv_from != NULL);
15832 DUK_ASSERT(tv_to != NULL);
15833 DUK_TVAL_SET_TVAL(tv_to, tv_from);
15834 DUK_TVAL_INCREF(thr, tv_to); /* no side effects */
15835}
15836
15837DUK_EXTERNAL void duk_insert(duk_context *ctx, duk_idx_t to_index) {
15838 duk_tval *p;
15839 duk_tval *q;
15840 duk_tval tv_tmp;
15841 duk_size_t nbytes;
15842
15843 DUK_ASSERT_CTX_VALID(ctx);
15844
15845 p = duk_require_tval(ctx, to_index);
15846 DUK_ASSERT(p != NULL);
15847 q = duk_require_tval(ctx, -1);
15848 DUK_ASSERT(q != NULL);
15849
15850 DUK_ASSERT(q >= p);
15851
15852 /* nbytes
15853 * <--------->
15854 * [ ... | p | x | x | q ]
15855 * => [ ... | q | p | x | x ]
15856 */
15857
15858 nbytes = (duk_size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p)); /* Note: 'q' is top-1 */
15859
15860 DUK_DDD(DUK_DDDPRINT("duk_insert: to_index=%ld, p=%p, q=%p, nbytes=%lu",
15861 (long) to_index, (void *) p, (void *) q, (unsigned long) nbytes));
15862
15863 /* No net refcount changes. */
15864
15865 if (nbytes > 0) {
15866 DUK_TVAL_SET_TVAL(&tv_tmp, q);
15867 DUK_ASSERT(nbytes > 0);
11fdf7f2 15868 DUK_MEMMOVE((void *) (p + 1), (const void *) p, (size_t) nbytes);
7c673cae
FG
15869 DUK_TVAL_SET_TVAL(p, &tv_tmp);
15870 } else {
15871 /* nop: insert top to top */
15872 DUK_ASSERT(nbytes == 0);
15873 DUK_ASSERT(p == q);
15874 }
15875}
15876
15877DUK_EXTERNAL void duk_replace(duk_context *ctx, duk_idx_t to_index) {
15878 duk_hthread *thr = (duk_hthread *) ctx;
15879 duk_tval *tv1;
15880 duk_tval *tv2;
15881 duk_tval tv_tmp;
15882
15883 DUK_ASSERT_CTX_VALID(ctx);
15884
15885 tv1 = duk_require_tval(ctx, -1);
15886 DUK_ASSERT(tv1 != NULL);
15887 tv2 = duk_require_tval(ctx, to_index);
15888 DUK_ASSERT(tv2 != NULL);
15889
15890 /* For tv1 == tv2, both pointing to stack top, the end result
15891 * is same as duk_pop(ctx).
15892 */
7c673cae
FG
15893 DUK_TVAL_SET_TVAL(&tv_tmp, tv2);
15894 DUK_TVAL_SET_TVAL(tv2, tv1);
11fdf7f2 15895 DUK_TVAL_SET_UNDEFINED(tv1);
7c673cae
FG
15896 thr->valstack_top--;
15897 DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
15898}
15899
15900DUK_EXTERNAL void duk_copy(duk_context *ctx, duk_idx_t from_index, duk_idx_t to_index) {
15901 duk_hthread *thr = (duk_hthread *) ctx;
15902 duk_tval *tv1;
15903 duk_tval *tv2;
7c673cae
FG
15904
15905 DUK_ASSERT_CTX_VALID(ctx);
15906 DUK_UNREF(thr); /* w/o refcounting */
15907
15908 tv1 = duk_require_tval(ctx, from_index);
15909 DUK_ASSERT(tv1 != NULL);
15910 tv2 = duk_require_tval(ctx, to_index);
15911 DUK_ASSERT(tv2 != NULL);
15912
15913 /* For tv1 == tv2, this is a no-op (no explicit check needed). */
11fdf7f2 15914 DUK_TVAL_SET_TVAL_UPDREF(thr, tv2, tv1); /* side effects */
7c673cae
FG
15915}
15916
15917DUK_EXTERNAL void duk_remove(duk_context *ctx, duk_idx_t index) {
15918 duk_hthread *thr = (duk_hthread *) ctx;
15919 duk_tval *p;
15920 duk_tval *q;
15921#ifdef DUK_USE_REFERENCE_COUNTING
15922 duk_tval tv_tmp;
15923#endif
15924 duk_size_t nbytes;
15925
15926 DUK_ASSERT_CTX_VALID(ctx);
15927
15928 p = duk_require_tval(ctx, index);
15929 DUK_ASSERT(p != NULL);
15930 q = duk_require_tval(ctx, -1);
15931 DUK_ASSERT(q != NULL);
15932
15933 DUK_ASSERT(q >= p);
15934
15935 /* nbytes zero size case
15936 * <--------->
15937 * [ ... | p | x | x | q ] [ ... | p==q ]
15938 * => [ ... | x | x | q ] [ ... ]
15939 */
15940
15941#ifdef DUK_USE_REFERENCE_COUNTING
15942 /* use a temp: decref only when valstack reachable values are correct */
15943 DUK_TVAL_SET_TVAL(&tv_tmp, p);
15944#endif
15945
15946 nbytes = (duk_size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p)); /* Note: 'q' is top-1 */
11fdf7f2 15947 DUK_MEMMOVE((void *) p, (const void *) (p + 1), (size_t) nbytes); /* zero size not an issue: pointers are valid */
7c673cae 15948
11fdf7f2 15949 DUK_TVAL_SET_UNDEFINED(q);
7c673cae
FG
15950 thr->valstack_top--;
15951
15952#ifdef DUK_USE_REFERENCE_COUNTING
15953 DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
15954#endif
15955}
15956
15957/*
15958 * Stack slice primitives
15959 */
15960
15961DUK_EXTERNAL void duk_xcopymove_raw(duk_context *to_ctx, duk_context *from_ctx, duk_idx_t count, duk_bool_t is_copy) {
15962 duk_hthread *to_thr = (duk_hthread *) to_ctx;
15963 duk_hthread *from_thr = (duk_hthread *) from_ctx;
15964 void *src;
15965 duk_size_t nbytes;
15966 duk_tval *p;
15967 duk_tval *q;
15968
15969 /* XXX: several pointer comparison issues here */
15970
15971 DUK_ASSERT_CTX_VALID(to_ctx);
15972 DUK_ASSERT_CTX_VALID(from_ctx);
15973 DUK_ASSERT(to_ctx != NULL);
15974 DUK_ASSERT(from_ctx != NULL);
15975
15976 if (to_ctx == from_ctx) {
11fdf7f2 15977 DUK_ERROR_API(to_thr, DUK_STR_INVALID_CONTEXT);
7c673cae
FG
15978 return;
15979 }
15980 if ((count < 0) ||
15981 (count > (duk_idx_t) to_thr->valstack_max)) {
15982 /* Maximum value check ensures 'nbytes' won't wrap below. */
11fdf7f2 15983 DUK_ERROR_API(to_thr, DUK_STR_INVALID_COUNT);
7c673cae
FG
15984 return;
15985 }
15986
15987 nbytes = sizeof(duk_tval) * count;
15988 if (nbytes == 0) {
15989 return;
15990 }
15991 DUK_ASSERT(to_thr->valstack_top <= to_thr->valstack_end);
15992 if ((duk_size_t) ((duk_uint8_t *) to_thr->valstack_end - (duk_uint8_t *) to_thr->valstack_top) < nbytes) {
11fdf7f2 15993 DUK_ERROR_API(to_thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
7c673cae
FG
15994 }
15995 src = (void *) ((duk_uint8_t *) from_thr->valstack_top - nbytes);
15996 if (src < (void *) from_thr->valstack_bottom) {
11fdf7f2 15997 DUK_ERROR_API(to_thr, DUK_STR_INVALID_COUNT);
7c673cae
FG
15998 }
15999
16000 /* copy values (no overlap even if to_ctx == from_ctx; that's not
16001 * allowed now anyway)
16002 */
16003 DUK_ASSERT(nbytes > 0);
11fdf7f2 16004 DUK_MEMCPY((void *) to_thr->valstack_top, (const void *) src, (size_t) nbytes);
7c673cae
FG
16005
16006 p = to_thr->valstack_top;
16007 to_thr->valstack_top = (duk_tval *) (void *) (((duk_uint8_t *) p) + nbytes);
16008
16009 if (is_copy) {
11fdf7f2 16010 /* Incref copies, keep originals. */
7c673cae
FG
16011 q = to_thr->valstack_top;
16012 while (p < q) {
16013 DUK_TVAL_INCREF(to_thr, p); /* no side effects */
16014 p++;
16015 }
16016 } else {
11fdf7f2 16017 /* No net refcount change. */
7c673cae
FG
16018 p = from_thr->valstack_top;
16019 q = (duk_tval *) (void *) (((duk_uint8_t *) p) - nbytes);
16020 from_thr->valstack_top = q;
16021
7c673cae
FG
16022 while (p > q) {
16023 p--;
11fdf7f2
TL
16024 DUK_TVAL_SET_UNDEFINED(p);
16025 /* XXX: fast primitive to set a bunch of values to UNDEFINED */
7c673cae
FG
16026 }
16027 }
16028}
16029
16030/*
16031 * Get/require
16032 */
16033
16034DUK_EXTERNAL void duk_require_undefined(duk_context *ctx, duk_idx_t index) {
16035 duk_hthread *thr = (duk_hthread *) ctx;
16036 duk_tval *tv;
16037
16038 DUK_ASSERT_CTX_VALID(ctx);
16039
16040 tv = duk_get_tval(ctx, index);
16041 if (tv && DUK_TVAL_IS_UNDEFINED(tv)) {
7c673cae
FG
16042 return;
16043 }
11fdf7f2
TL
16044 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "undefined", DUK_STR_NOT_UNDEFINED);
16045 return; /* not reachable */
7c673cae
FG
16046}
16047
16048DUK_EXTERNAL void duk_require_null(duk_context *ctx, duk_idx_t index) {
16049 duk_hthread *thr = (duk_hthread *) ctx;
16050 duk_tval *tv;
16051
16052 DUK_ASSERT_CTX_VALID(ctx);
16053
16054 tv = duk_get_tval(ctx, index);
16055 if (tv && DUK_TVAL_IS_NULL(tv)) {
16056 return;
16057 }
11fdf7f2 16058 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "null", DUK_STR_NOT_NULL);
7c673cae
FG
16059 return; /* not reachable */
16060}
16061
16062DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t index) {
16063 duk_bool_t ret = 0; /* default: false */
16064 duk_tval *tv;
16065
16066 DUK_ASSERT_CTX_VALID(ctx);
16067
16068 tv = duk_get_tval(ctx, index);
16069 if (tv && DUK_TVAL_IS_BOOLEAN(tv)) {
16070 ret = DUK_TVAL_GET_BOOLEAN(tv);
16071 }
16072
16073 DUK_ASSERT(ret == 0 || ret == 1);
16074 return ret;
16075}
16076
16077DUK_EXTERNAL duk_bool_t duk_require_boolean(duk_context *ctx, duk_idx_t index) {
16078 duk_hthread *thr = (duk_hthread *) ctx;
16079 duk_tval *tv;
16080
16081 DUK_ASSERT_CTX_VALID(ctx);
16082
16083 tv = duk_get_tval(ctx, index);
16084 if (tv && DUK_TVAL_IS_BOOLEAN(tv)) {
16085 duk_bool_t ret = DUK_TVAL_GET_BOOLEAN(tv);
16086 DUK_ASSERT(ret == 0 || ret == 1);
16087 return ret;
16088 }
11fdf7f2 16089 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "boolean", DUK_STR_NOT_BOOLEAN);
7c673cae
FG
16090 return 0; /* not reachable */
16091}
16092
16093DUK_EXTERNAL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t index) {
16094 duk_double_union ret;
16095 duk_tval *tv;
16096
16097 DUK_ASSERT_CTX_VALID(ctx);
16098
16099 ret.d = DUK_DOUBLE_NAN; /* default: NaN */
16100 tv = duk_get_tval(ctx, index);
16101 if (tv && DUK_TVAL_IS_NUMBER(tv)) {
16102 ret.d = DUK_TVAL_GET_NUMBER(tv);
16103 }
16104
16105 /*
16106 * Number should already be in NaN-normalized form, but let's
16107 * normalize anyway.
16108 */
16109
16110 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&ret);
16111 return ret.d;
16112}
16113
16114DUK_EXTERNAL duk_double_t duk_require_number(duk_context *ctx, duk_idx_t index) {
16115 duk_hthread *thr = (duk_hthread *) ctx;
16116 duk_tval *tv;
16117
16118 DUK_ASSERT_CTX_VALID(ctx);
16119
16120 tv = duk_get_tval(ctx, index);
16121 if (tv && DUK_TVAL_IS_NUMBER(tv)) {
16122 duk_double_union ret;
16123 ret.d = DUK_TVAL_GET_NUMBER(tv);
16124
16125 /*
16126 * Number should already be in NaN-normalized form,
16127 * but let's normalize anyway.
16128 */
16129
16130 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&ret);
16131 return ret.d;
16132 }
11fdf7f2 16133 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "number", DUK_STR_NOT_NUMBER);
7c673cae
FG
16134 return DUK_DOUBLE_NAN; /* not reachable */
16135}
16136
16137DUK_EXTERNAL duk_int_t duk_get_int(duk_context *ctx, duk_idx_t index) {
16138 /* Custom coercion for API */
16139 DUK_ASSERT_CTX_VALID(ctx);
16140 return (duk_int_t) duk__api_coerce_d2i(ctx, index, 0 /*require*/);
16141}
16142
16143DUK_EXTERNAL duk_uint_t duk_get_uint(duk_context *ctx, duk_idx_t index) {
16144 /* Custom coercion for API */
16145 DUK_ASSERT_CTX_VALID(ctx);
16146 return (duk_uint_t) duk__api_coerce_d2ui(ctx, index, 0 /*require*/);
16147}
16148
16149DUK_EXTERNAL duk_int_t duk_require_int(duk_context *ctx, duk_idx_t index) {
16150 /* Custom coercion for API */
16151 DUK_ASSERT_CTX_VALID(ctx);
16152 return (duk_int_t) duk__api_coerce_d2i(ctx, index, 1 /*require*/);
16153}
16154
16155DUK_EXTERNAL duk_uint_t duk_require_uint(duk_context *ctx, duk_idx_t index) {
16156 /* Custom coercion for API */
16157 DUK_ASSERT_CTX_VALID(ctx);
16158 return (duk_uint_t) duk__api_coerce_d2ui(ctx, index, 1 /*require*/);
16159}
16160
16161DUK_EXTERNAL const char *duk_get_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) {
16162 const char *ret;
16163 duk_tval *tv;
16164
16165 DUK_ASSERT_CTX_VALID(ctx);
16166
16167 /* default: NULL, length 0 */
16168 ret = NULL;
16169 if (out_len) {
16170 *out_len = 0;
16171 }
16172
16173 tv = duk_get_tval(ctx, index);
16174 if (tv && DUK_TVAL_IS_STRING(tv)) {
16175 /* Here we rely on duk_hstring instances always being zero
16176 * terminated even if the actual string is not.
16177 */
16178 duk_hstring *h = DUK_TVAL_GET_STRING(tv);
16179 DUK_ASSERT(h != NULL);
16180 ret = (const char *) DUK_HSTRING_GET_DATA(h);
16181 if (out_len) {
16182 *out_len = DUK_HSTRING_GET_BYTELEN(h);
16183 }
16184 }
16185
16186 return ret;
16187}
16188
16189DUK_EXTERNAL const char *duk_require_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) {
16190 duk_hthread *thr = (duk_hthread *) ctx;
16191 const char *ret;
16192
16193 DUK_ASSERT_CTX_VALID(ctx);
16194
16195 /* Note: this check relies on the fact that even a zero-size string
16196 * has a non-NULL pointer.
16197 */
16198 ret = duk_get_lstring(ctx, index, out_len);
16199 if (ret) {
16200 return ret;
16201 }
11fdf7f2 16202 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "string", DUK_STR_NOT_STRING);
7c673cae
FG
16203 return NULL; /* not reachable */
16204}
16205
16206DUK_EXTERNAL const char *duk_get_string(duk_context *ctx, duk_idx_t index) {
16207 DUK_ASSERT_CTX_VALID(ctx);
16208
16209 return duk_get_lstring(ctx, index, NULL);
16210}
16211
16212DUK_EXTERNAL const char *duk_require_string(duk_context *ctx, duk_idx_t index) {
16213 DUK_ASSERT_CTX_VALID(ctx);
16214
16215 return duk_require_lstring(ctx, index, NULL);
16216}
16217
16218DUK_EXTERNAL void *duk_get_pointer(duk_context *ctx, duk_idx_t index) {
16219 duk_tval *tv;
16220
16221 DUK_ASSERT_CTX_VALID(ctx);
16222
16223 tv = duk_get_tval(ctx, index);
16224 if (tv && DUK_TVAL_IS_POINTER(tv)) {
16225 void *p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */
16226 return (void *) p;
16227 }
16228
16229 return NULL;
16230}
16231
16232DUK_EXTERNAL void *duk_require_pointer(duk_context *ctx, duk_idx_t index) {
16233 duk_hthread *thr = (duk_hthread *) ctx;
16234 duk_tval *tv;
16235
16236 DUK_ASSERT_CTX_VALID(ctx);
16237
16238 /* Note: here we must be wary of the fact that a pointer may be
16239 * valid and be a NULL.
16240 */
16241 tv = duk_get_tval(ctx, index);
16242 if (tv && DUK_TVAL_IS_POINTER(tv)) {
16243 void *p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */
16244 return (void *) p;
16245 }
11fdf7f2 16246 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "pointer", DUK_STR_NOT_POINTER);
7c673cae
FG
16247 return NULL; /* not reachable */
16248}
16249
16250#if 0 /*unused*/
16251DUK_INTERNAL void *duk_get_voidptr(duk_context *ctx, duk_idx_t index) {
16252 duk_tval *tv;
16253
16254 DUK_ASSERT_CTX_VALID(ctx);
16255
16256 tv = duk_get_tval(ctx, index);
16257 if (tv && DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
16258 duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
16259 DUK_ASSERT(h != NULL);
16260 return (void *) h;
16261 }
16262
16263 return NULL;
16264}
16265#endif
16266
16267DUK_LOCAL void *duk__get_buffer_helper(duk_context *ctx, duk_idx_t index, duk_size_t *out_size, duk_bool_t throw_flag) {
16268 duk_hthread *thr = (duk_hthread *) ctx;
16269 duk_tval *tv;
16270
16271 DUK_ASSERT_CTX_VALID(ctx);
16272 DUK_UNREF(thr);
16273
16274 if (out_size != NULL) {
16275 *out_size = 0;
16276 }
16277
16278 tv = duk_get_tval(ctx, index);
16279 if (tv && DUK_TVAL_IS_BUFFER(tv)) {
16280 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
16281 DUK_ASSERT(h != NULL);
16282 if (out_size) {
16283 *out_size = DUK_HBUFFER_GET_SIZE(h);
16284 }
16285 return (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); /* may be NULL (but only if size is 0) */
16286 }
16287
16288 if (throw_flag) {
11fdf7f2 16289 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "buffer", DUK_STR_NOT_BUFFER);
7c673cae
FG
16290 }
16291 return NULL;
16292}
16293
16294DUK_EXTERNAL void *duk_get_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) {
16295 return duk__get_buffer_helper(ctx, index, out_size, 0 /*throw_flag*/);
16296}
16297
16298DUK_EXTERNAL void *duk_require_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) {
16299 return duk__get_buffer_helper(ctx, index, out_size, 1 /*throw_flag*/);
16300}
16301
16302DUK_LOCAL void *duk__get_buffer_data_helper(duk_context *ctx, duk_idx_t index, duk_size_t *out_size, duk_bool_t throw_flag) {
16303 duk_hthread *thr = (duk_hthread *) ctx;
16304 duk_tval *tv;
16305
16306 DUK_ASSERT_CTX_VALID(ctx);
16307 DUK_UNREF(thr);
16308
16309 if (out_size != NULL) {
16310 *out_size = 0;
16311 }
16312
16313 tv = duk_get_tval(ctx, index);
16314 if (tv == NULL) {
16315 goto fail;
16316 }
16317
16318 if (DUK_TVAL_IS_BUFFER(tv)) {
16319 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
16320 DUK_ASSERT(h != NULL);
16321 if (out_size) {
16322 *out_size = DUK_HBUFFER_GET_SIZE(h);
16323 }
16324 return (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); /* may be NULL (but only if size is 0) */
16325 } else if (DUK_TVAL_IS_OBJECT(tv)) {
16326 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
16327 DUK_ASSERT(h != NULL);
16328 if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
16329 /* XXX: this is probably a useful shared helper: for a
16330 * duk_hbufferobject, get a validated buffer pointer/length.
16331 */
16332 duk_hbufferobject *h_bufobj = (duk_hbufferobject *) h;
16333 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
16334
16335 if (h_bufobj->buf != NULL &&
16336 DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj)) {
16337 duk_uint8_t *p;
16338
16339 p = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf);
16340 if (out_size != NULL) {
16341 *out_size = (duk_size_t) h_bufobj->length;
16342 }
16343 return (void *) (p + h_bufobj->offset);
16344 }
16345 /* if slice not fully valid, treat as error */
16346 }
16347 }
16348
16349 fail:
16350 if (throw_flag) {
11fdf7f2 16351 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "buffer", DUK_STR_NOT_BUFFER);
7c673cae
FG
16352 }
16353 return NULL;
16354}
16355
16356DUK_EXTERNAL void *duk_get_buffer_data(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) {
16357 return duk__get_buffer_data_helper(ctx, index, out_size, 0 /*throw_flag*/);
16358}
16359
16360DUK_EXTERNAL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) {
16361 return duk__get_buffer_data_helper(ctx, index, out_size, 1 /*throw_flag*/);
16362}
16363
11fdf7f2
TL
16364/* Raw helper for getting a value from the stack, checking its tag.
16365 * The tag cannot be a number because numbers don't have an internal
16366 * tag in the packed representation.
7c673cae 16367 */
11fdf7f2
TL
16368
16369DUK_LOCAL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t index, duk_uint_t tag) {
7c673cae 16370 duk_tval *tv;
7c673cae
FG
16371
16372 DUK_ASSERT_CTX_VALID(ctx);
16373
16374 tv = duk_get_tval(ctx, index);
16375 if (tv && (DUK_TVAL_GET_TAG(tv) == tag)) {
16376 duk_heaphdr *ret;
7c673cae
FG
16377 ret = DUK_TVAL_GET_HEAPHDR(tv);
16378 DUK_ASSERT(ret != NULL); /* tagged null pointers should never occur */
11fdf7f2 16379 return ret;
7c673cae
FG
16380 }
16381
11fdf7f2 16382 return (duk_heaphdr *) NULL;
7c673cae
FG
16383}
16384
16385DUK_INTERNAL duk_hstring *duk_get_hstring(duk_context *ctx, duk_idx_t index) {
11fdf7f2 16386 return (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_STRING);
7c673cae
FG
16387}
16388
16389DUK_INTERNAL duk_hstring *duk_require_hstring(duk_context *ctx, duk_idx_t index) {
11fdf7f2
TL
16390 duk_heaphdr *h;
16391 h = duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_STRING);
16392 if (h == NULL) {
16393 DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, index, "string", DUK_STR_NOT_STRING);
16394 }
16395 return (duk_hstring *) h;
7c673cae
FG
16396}
16397
16398DUK_INTERNAL duk_hobject *duk_get_hobject(duk_context *ctx, duk_idx_t index) {
11fdf7f2 16399 return (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
7c673cae
FG
16400}
16401
16402DUK_INTERNAL duk_hobject *duk_require_hobject(duk_context *ctx, duk_idx_t index) {
11fdf7f2
TL
16403 duk_heaphdr *h;
16404 h = duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
16405 if (h == NULL) {
16406 DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, index, "object", DUK_STR_NOT_OBJECT);
16407 }
16408 return (duk_hobject *) h;
7c673cae
FG
16409}
16410
16411DUK_INTERNAL duk_hbuffer *duk_get_hbuffer(duk_context *ctx, duk_idx_t index) {
11fdf7f2 16412 return (duk_hbuffer *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_BUFFER);
7c673cae
FG
16413}
16414
16415DUK_INTERNAL duk_hbuffer *duk_require_hbuffer(duk_context *ctx, duk_idx_t index) {
11fdf7f2
TL
16416 duk_heaphdr *h;
16417 h = duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_BUFFER);
16418 if (h == NULL) {
16419 DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, index, "buffer", DUK_STR_NOT_BUFFER);
16420 }
16421 return (duk_hbuffer *) h;
7c673cae
FG
16422}
16423
16424DUK_INTERNAL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t index) {
11fdf7f2 16425 duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
7c673cae
FG
16426 if (h != NULL && !DUK_HOBJECT_IS_THREAD(h)) {
16427 h = NULL;
16428 }
16429 return (duk_hthread *) h;
16430}
16431
16432DUK_INTERNAL duk_hthread *duk_require_hthread(duk_context *ctx, duk_idx_t index) {
16433 duk_hthread *thr = (duk_hthread *) ctx;
11fdf7f2
TL
16434 duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
16435 if (!(h != NULL && DUK_HOBJECT_IS_THREAD(h))) {
16436 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "thread", DUK_STR_NOT_THREAD);
7c673cae
FG
16437 }
16438 return (duk_hthread *) h;
16439}
16440
16441DUK_INTERNAL duk_hcompiledfunction *duk_get_hcompiledfunction(duk_context *ctx, duk_idx_t index) {
11fdf7f2 16442 duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
7c673cae
FG
16443 if (h != NULL && !DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
16444 h = NULL;
16445 }
16446 return (duk_hcompiledfunction *) h;
16447}
16448
16449DUK_INTERNAL duk_hcompiledfunction *duk_require_hcompiledfunction(duk_context *ctx, duk_idx_t index) {
16450 duk_hthread *thr = (duk_hthread *) ctx;
11fdf7f2
TL
16451 duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
16452 if (!(h != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION(h))) {
16453 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "compiledfunction", DUK_STR_NOT_COMPILEDFUNCTION);
7c673cae
FG
16454 }
16455 return (duk_hcompiledfunction *) h;
16456}
16457
16458DUK_INTERNAL duk_hnativefunction *duk_get_hnativefunction(duk_context *ctx, duk_idx_t index) {
11fdf7f2 16459 duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
7c673cae
FG
16460 if (h != NULL && !DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
16461 h = NULL;
16462 }
16463 return (duk_hnativefunction *) h;
16464}
16465
16466DUK_INTERNAL duk_hnativefunction *duk_require_hnativefunction(duk_context *ctx, duk_idx_t index) {
16467 duk_hthread *thr = (duk_hthread *) ctx;
11fdf7f2
TL
16468 duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
16469 if (!(h != NULL && DUK_HOBJECT_IS_NATIVEFUNCTION(h))) {
16470 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "nativefunction", DUK_STR_NOT_NATIVEFUNCTION);
7c673cae
FG
16471 }
16472 return (duk_hnativefunction *) h;
16473}
16474
16475DUK_EXTERNAL duk_c_function duk_get_c_function(duk_context *ctx, duk_idx_t index) {
16476 duk_tval *tv;
16477 duk_hobject *h;
16478 duk_hnativefunction *f;
16479
16480 DUK_ASSERT_CTX_VALID(ctx);
16481
16482 tv = duk_get_tval(ctx, index);
16483 if (!tv) {
16484 return NULL;
16485 }
16486 if (!DUK_TVAL_IS_OBJECT(tv)) {
16487 return NULL;
16488 }
16489 h = DUK_TVAL_GET_OBJECT(tv);
16490 DUK_ASSERT(h != NULL);
16491
16492 if (!DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
16493 return NULL;
16494 }
16495 DUK_ASSERT(DUK_HOBJECT_HAS_NATIVEFUNCTION(h));
16496 f = (duk_hnativefunction *) h;
16497
16498 return f->func;
16499}
16500
16501DUK_EXTERNAL duk_c_function duk_require_c_function(duk_context *ctx, duk_idx_t index) {
16502 duk_hthread *thr = (duk_hthread *) ctx;
16503 duk_c_function ret;
16504
16505 DUK_ASSERT_CTX_VALID(ctx);
16506
16507 ret = duk_get_c_function(ctx, index);
16508 if (!ret) {
11fdf7f2 16509 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "nativefunction", DUK_STR_NOT_NATIVEFUNCTION);
7c673cae
FG
16510 }
16511 return ret;
16512}
16513
11fdf7f2
TL
16514DUK_EXTERNAL void duk_require_function(duk_context *ctx, duk_idx_t index) {
16515 if (!duk_is_function(ctx, index)) {
16516 DUK_ERROR_REQUIRE_TYPE_INDEX((duk_hthread *) ctx, index, "function", DUK_STR_NOT_FUNCTION);
16517 }
16518}
16519
7c673cae
FG
16520DUK_EXTERNAL duk_context *duk_get_context(duk_context *ctx, duk_idx_t index) {
16521 DUK_ASSERT_CTX_VALID(ctx);
16522
16523 return (duk_context *) duk_get_hthread(ctx, index);
16524}
16525
16526DUK_EXTERNAL duk_context *duk_require_context(duk_context *ctx, duk_idx_t index) {
16527 DUK_ASSERT_CTX_VALID(ctx);
16528
16529 return (duk_context *) duk_require_hthread(ctx, index);
16530}
16531
16532DUK_EXTERNAL void *duk_get_heapptr(duk_context *ctx, duk_idx_t index) {
16533 duk_tval *tv;
16534 void *ret;
16535
16536 DUK_ASSERT_CTX_VALID(ctx);
16537
16538 tv = duk_get_tval(ctx, index);
16539 if (tv && DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
16540 ret = (void *) DUK_TVAL_GET_HEAPHDR(tv);
16541 DUK_ASSERT(ret != NULL);
16542 return ret;
16543 }
16544
16545 return (void *) NULL;
16546}
16547
16548DUK_EXTERNAL void *duk_require_heapptr(duk_context *ctx, duk_idx_t index) {
16549 duk_hthread *thr = (duk_hthread *) ctx;
16550 duk_tval *tv;
16551 void *ret;
16552
16553 DUK_ASSERT_CTX_VALID(ctx);
16554
16555 tv = duk_require_tval(ctx, index);
16556 DUK_ASSERT(tv != NULL);
16557 if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
16558 ret = (void *) DUK_TVAL_GET_HEAPHDR(tv);
16559 DUK_ASSERT(ret != NULL);
16560 return ret;
16561 }
16562
11fdf7f2 16563 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "heapobject", DUK_STR_UNEXPECTED_TYPE);
7c673cae
FG
16564 return (void *) NULL; /* not reachable */
16565}
16566
16567#if 0
16568/* This would be pointless: we'd return NULL for both lightfuncs and
16569 * unexpected types.
16570 */
11fdf7f2 16571DUK_INTERNAL duk_hobject *duk_get_hobject_or_lfunc(duk_context *ctx, duk_idx_t index) {
7c673cae
FG
16572}
16573#endif
16574
16575/* Useful for internal call sites where we either expect an object (function)
16576 * or a lightfunc. Accepts an object (returned as is) or a lightfunc (coerced
16577 * to an object). Return value is NULL if value is neither an object nor a
16578 * lightfunc.
16579 */
11fdf7f2 16580DUK_INTERNAL duk_hobject *duk_get_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index) {
7c673cae
FG
16581 duk_tval *tv;
16582
16583 DUK_ASSERT_CTX_VALID(ctx);
16584
16585 tv = duk_require_tval(ctx, index);
16586 DUK_ASSERT(tv != NULL);
16587 if (DUK_TVAL_IS_OBJECT(tv)) {
16588 return DUK_TVAL_GET_OBJECT(tv);
16589 } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
16590 duk_to_object(ctx, index);
16591 return duk_require_hobject(ctx, index);
16592 }
16593
16594 return NULL;
16595}
16596
16597/* Useful for internal call sites where we either expect an object (function)
16598 * or a lightfunc. Returns NULL for a lightfunc.
16599 */
16600DUK_INTERNAL duk_hobject *duk_require_hobject_or_lfunc(duk_context *ctx, duk_idx_t index) {
16601 duk_hthread *thr = (duk_hthread *) ctx;
16602 duk_tval *tv;
16603
16604 DUK_ASSERT_CTX_VALID(ctx);
16605
16606 tv = duk_require_tval(ctx, index);
16607 DUK_ASSERT(tv != NULL);
16608 if (DUK_TVAL_IS_OBJECT(tv)) {
16609 return DUK_TVAL_GET_OBJECT(tv);
16610 } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
16611 return NULL;
16612 }
11fdf7f2 16613 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "object", DUK_STR_NOT_OBJECT);
7c673cae
FG
16614 return NULL; /* not reachable */
16615}
16616
16617/* Useful for internal call sites where we either expect an object (function)
16618 * or a lightfunc. Accepts an object (returned as is) or a lightfunc (coerced
16619 * to an object). Return value is never NULL.
16620 */
16621DUK_INTERNAL duk_hobject *duk_require_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index) {
16622 duk_hthread *thr = (duk_hthread *) ctx;
16623 duk_tval *tv;
16624
16625 DUK_ASSERT_CTX_VALID(ctx);
16626
16627 tv = duk_require_tval(ctx, index);
16628 if (DUK_TVAL_IS_OBJECT(tv)) {
16629 return DUK_TVAL_GET_OBJECT(tv);
16630 } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
16631 duk_to_object(ctx, index);
16632 return duk_require_hobject(ctx, index);
16633 }
11fdf7f2 16634 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "object", DUK_STR_NOT_OBJECT);
7c673cae
FG
16635 return NULL; /* not reachable */
16636}
16637
11fdf7f2
TL
16638DUK_INTERNAL duk_hobject *duk_get_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum) {
16639 duk_hobject *h;
16640
16641 DUK_ASSERT_CTX_VALID(ctx);
16642 DUK_ASSERT_DISABLE(classnum >= 0); /* unsigned */
16643 DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX);
16644
16645 h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
16646 if (h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) != classnum) {
16647 h = NULL;
16648 }
16649 return h;
16650}
16651
16652DUK_INTERNAL duk_hobject *duk_require_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum) {
16653 duk_hthread *thr;
16654 duk_hobject *h;
16655
16656 DUK_ASSERT_CTX_VALID(ctx);
16657 DUK_ASSERT_DISABLE(classnum >= 0); /* unsigned */
16658 DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX);
16659 thr = (duk_hthread *) ctx;
16660
16661 h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
16662 if (!(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) == classnum)) {
16663 duk_hstring *h_class;
16664 h_class = DUK_HTHREAD_GET_STRING(thr, DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum));
16665 DUK_UNREF(h_class);
16666
16667 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, (const char *) DUK_HSTRING_GET_DATA(h_class), DUK_STR_UNEXPECTED_TYPE);
16668 }
16669 return h;
16670}
16671
7c673cae
FG
16672DUK_EXTERNAL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t index) {
16673 duk_tval *tv;
16674
16675 DUK_ASSERT_CTX_VALID(ctx);
16676
16677 tv = duk_get_tval(ctx, index);
16678 if (!tv) {
16679 return 0;
16680 }
16681
16682 switch (DUK_TVAL_GET_TAG(tv)) {
16683 case DUK_TAG_UNDEFINED:
16684 case DUK_TAG_NULL:
16685 case DUK_TAG_BOOLEAN:
16686 case DUK_TAG_POINTER:
16687 return 0;
16688 case DUK_TAG_STRING: {
16689 duk_hstring *h = DUK_TVAL_GET_STRING(tv);
16690 DUK_ASSERT(h != NULL);
16691 return (duk_size_t) DUK_HSTRING_GET_CHARLEN(h);
16692 }
16693 case DUK_TAG_OBJECT: {
16694 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
16695 DUK_ASSERT(h != NULL);
16696 return (duk_size_t) duk_hobject_get_length((duk_hthread *) ctx, h);
16697 }
16698 case DUK_TAG_BUFFER: {
16699 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
16700 DUK_ASSERT(h != NULL);
16701 return (duk_size_t) DUK_HBUFFER_GET_SIZE(h);
16702 }
16703 case DUK_TAG_LIGHTFUNC: {
16704 duk_small_uint_t lf_flags;
16705 lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
16706 return (duk_size_t) DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
16707 }
16708#if defined(DUK_USE_FASTINT)
16709 case DUK_TAG_FASTINT:
16710#endif
16711 default:
16712 /* number */
11fdf7f2 16713 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
7c673cae
FG
16714 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
16715 return 0;
16716 }
16717
16718 DUK_UNREACHABLE();
16719}
16720
16721DUK_INTERNAL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_size_t length) {
16722 duk_hthread *thr = (duk_hthread *) ctx;
16723 duk_hobject *h;
16724
16725 DUK_ASSERT_CTX_VALID(ctx);
16726
16727 h = duk_get_hobject(ctx, index);
16728 if (!h) {
16729 return;
16730 }
16731
16732 duk_hobject_set_length(thr, h, (duk_uint32_t) length); /* XXX: typing */
16733}
16734
16735/*
16736 * Conversions and coercions
16737 *
16738 * The conversion/coercions are in-place operations on the value stack.
16739 * Some operations are implemented here directly, while others call a
16740 * helper in duk_js_ops.c after validating arguments.
16741 */
16742
16743/* E5 Section 8.12.8 */
16744
16745DUK_LOCAL duk_bool_t duk__defaultvalue_coerce_attempt(duk_context *ctx, duk_idx_t index, duk_small_int_t func_stridx) {
16746 if (duk_get_prop_stridx(ctx, index, func_stridx)) {
16747 /* [ ... func ] */
16748 if (duk_is_callable(ctx, -1)) {
16749 duk_dup(ctx, index); /* -> [ ... func this ] */
16750 duk_call_method(ctx, 0); /* -> [ ... retval ] */
16751 if (duk_is_primitive(ctx, -1)) {
16752 duk_replace(ctx, index);
16753 return 1;
16754 }
16755 /* [ ... retval ]; popped below */
16756 }
16757 }
16758 duk_pop(ctx); /* [ ... func/retval ] -> [ ... ] */
16759 return 0;
16760}
16761
16762DUK_EXTERNAL void duk_to_defaultvalue(duk_context *ctx, duk_idx_t index, duk_int_t hint) {
16763 duk_hthread *thr = (duk_hthread *) ctx;
16764 duk_hobject *obj;
16765 /* inline initializer for coercers[] is not allowed by old compilers like BCC */
16766 duk_small_int_t coercers[2];
16767
16768 DUK_ASSERT_CTX_VALID(ctx);
16769 DUK_ASSERT(thr != NULL);
16770
16771 coercers[0] = DUK_STRIDX_VALUE_OF;
16772 coercers[1] = DUK_STRIDX_TO_STRING;
16773
16774 index = duk_require_normalize_index(ctx, index);
16775 obj = duk_require_hobject_or_lfunc(ctx, index);
16776
16777 if (hint == DUK_HINT_NONE) {
16778 if (obj != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_DATE) {
16779 hint = DUK_HINT_STRING;
16780 } else {
16781 hint = DUK_HINT_NUMBER;
16782 }
16783 }
16784
16785 if (hint == DUK_HINT_STRING) {
16786 coercers[0] = DUK_STRIDX_TO_STRING;
16787 coercers[1] = DUK_STRIDX_VALUE_OF;
16788 }
16789
16790 if (duk__defaultvalue_coerce_attempt(ctx, index, coercers[0])) {
16791 return;
16792 }
16793
16794 if (duk__defaultvalue_coerce_attempt(ctx, index, coercers[1])) {
16795 return;
16796 }
16797
11fdf7f2 16798 DUK_ERROR_TYPE(thr, DUK_STR_DEFAULTVALUE_COERCE_FAILED);
7c673cae
FG
16799}
16800
16801DUK_EXTERNAL void duk_to_undefined(duk_context *ctx, duk_idx_t index) {
16802 duk_hthread *thr = (duk_hthread *) ctx;
16803 duk_tval *tv;
7c673cae
FG
16804
16805 DUK_ASSERT_CTX_VALID(ctx);
16806 DUK_UNREF(thr);
16807
16808 tv = duk_require_tval(ctx, index);
16809 DUK_ASSERT(tv != NULL);
11fdf7f2 16810 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
7c673cae
FG
16811}
16812
16813DUK_EXTERNAL void duk_to_null(duk_context *ctx, duk_idx_t index) {
16814 duk_hthread *thr = (duk_hthread *) ctx;
16815 duk_tval *tv;
7c673cae
FG
16816
16817 DUK_ASSERT_CTX_VALID(ctx);
16818 DUK_UNREF(thr);
16819
16820 tv = duk_require_tval(ctx, index);
16821 DUK_ASSERT(tv != NULL);
11fdf7f2 16822 DUK_TVAL_SET_NULL_UPDREF(thr, tv); /* side effects */
7c673cae
FG
16823}
16824
16825/* E5 Section 9.1 */
16826DUK_EXTERNAL void duk_to_primitive(duk_context *ctx, duk_idx_t index, duk_int_t hint) {
16827 DUK_ASSERT_CTX_VALID(ctx);
16828 DUK_ASSERT(hint == DUK_HINT_NONE || hint == DUK_HINT_NUMBER || hint == DUK_HINT_STRING);
16829
16830 index = duk_require_normalize_index(ctx, index);
16831
16832 if (!duk_check_type_mask(ctx, index, DUK_TYPE_MASK_OBJECT |
16833 DUK_TYPE_MASK_LIGHTFUNC)) {
16834 /* everything except object stay as is */
16835 return;
16836 }
16837 duk_to_defaultvalue(ctx, index, hint);
16838}
16839
16840/* E5 Section 9.2 */
16841DUK_EXTERNAL duk_bool_t duk_to_boolean(duk_context *ctx, duk_idx_t index) {
16842 duk_hthread *thr = (duk_hthread *) ctx;
16843 duk_tval *tv;
7c673cae
FG
16844 duk_bool_t val;
16845
16846 DUK_ASSERT_CTX_VALID(ctx);
16847 DUK_UNREF(thr);
16848
16849 index = duk_require_normalize_index(ctx, index);
16850
16851 tv = duk_require_tval(ctx, index);
16852 DUK_ASSERT(tv != NULL);
16853
16854 val = duk_js_toboolean(tv);
16855 DUK_ASSERT(val == 0 || val == 1);
16856
16857 /* Note: no need to re-lookup tv, conversion is side effect free */
16858 DUK_ASSERT(tv != NULL);
11fdf7f2 16859 DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv, val); /* side effects */
7c673cae
FG
16860 return val;
16861}
16862
16863DUK_EXTERNAL duk_double_t duk_to_number(duk_context *ctx, duk_idx_t index) {
16864 duk_hthread *thr = (duk_hthread *) ctx;
16865 duk_tval *tv;
7c673cae
FG
16866 duk_double_t d;
16867
16868 DUK_ASSERT_CTX_VALID(ctx);
16869
16870 tv = duk_require_tval(ctx, index);
16871 DUK_ASSERT(tv != NULL);
16872 /* XXX: fastint? */
16873 d = duk_js_tonumber(thr, tv);
16874
16875 /* Note: need to re-lookup because ToNumber() may have side effects */
16876 tv = duk_require_tval(ctx, index);
11fdf7f2 16877 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, d); /* side effects */
7c673cae
FG
16878 return d;
16879}
16880
16881/* XXX: combine all the integer conversions: they share everything
16882 * but the helper function for coercion.
16883 */
16884
16885typedef duk_double_t (*duk__toint_coercer)(duk_hthread *thr, duk_tval *tv);
16886
16887DUK_LOCAL duk_double_t duk__to_int_uint_helper(duk_context *ctx, duk_idx_t index, duk__toint_coercer coerce_func) {
16888 duk_hthread *thr = (duk_hthread *) ctx;
16889 duk_tval *tv;
7c673cae
FG
16890 duk_double_t d;
16891
16892 DUK_ASSERT_CTX_VALID(ctx);
16893
16894 tv = duk_require_tval(ctx, index);
16895 DUK_ASSERT(tv != NULL);
16896 d = coerce_func(thr, tv);
16897
16898 /* XXX: fastint? */
16899
16900 /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
16901 tv = duk_require_tval(ctx, index);
11fdf7f2 16902 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, d); /* side effects */
7c673cae
FG
16903 return d;
16904}
16905
16906DUK_EXTERNAL duk_int_t duk_to_int(duk_context *ctx, duk_idx_t index) {
16907 /* Value coercion (in stack): ToInteger(), E5 Section 9.4
16908 * API return value coercion: custom
16909 */
16910 DUK_ASSERT_CTX_VALID(ctx);
16911 (void) duk__to_int_uint_helper(ctx, index, duk_js_tointeger);
16912 return (duk_int_t) duk__api_coerce_d2i(ctx, index, 0 /*require*/);
16913}
16914
16915DUK_EXTERNAL duk_uint_t duk_to_uint(duk_context *ctx, duk_idx_t index) {
16916 /* Value coercion (in stack): ToInteger(), E5 Section 9.4
16917 * API return value coercion: custom
16918 */
16919 DUK_ASSERT_CTX_VALID(ctx);
16920 (void) duk__to_int_uint_helper(ctx, index, duk_js_tointeger);
16921 return (duk_uint_t) duk__api_coerce_d2ui(ctx, index, 0 /*require*/);
16922}
16923
16924DUK_EXTERNAL duk_int32_t duk_to_int32(duk_context *ctx, duk_idx_t index) {
16925 duk_hthread *thr = (duk_hthread *) ctx;
16926 duk_tval *tv;
7c673cae
FG
16927 duk_int32_t ret;
16928
16929 DUK_ASSERT_CTX_VALID(ctx);
16930
16931 tv = duk_require_tval(ctx, index);
16932 DUK_ASSERT(tv != NULL);
16933 ret = duk_js_toint32(thr, tv);
16934
16935 /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
16936 tv = duk_require_tval(ctx, index);
11fdf7f2 16937 DUK_TVAL_SET_FASTINT_I32_UPDREF(thr, tv, ret); /* side effects */
7c673cae 16938 return ret;
7c673cae
FG
16939}
16940
16941DUK_EXTERNAL duk_uint32_t duk_to_uint32(duk_context *ctx, duk_idx_t index) {
16942 duk_hthread *thr = (duk_hthread *) ctx;
16943 duk_tval *tv;
7c673cae
FG
16944 duk_uint32_t ret;
16945
16946 DUK_ASSERT_CTX_VALID(ctx);
16947
16948 tv = duk_require_tval(ctx, index);
16949 DUK_ASSERT(tv != NULL);
16950 ret = duk_js_touint32(thr, tv);
16951
16952 /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
16953 tv = duk_require_tval(ctx, index);
11fdf7f2 16954 DUK_TVAL_SET_FASTINT_U32_UPDREF(thr, tv, ret); /* side effects */
7c673cae
FG
16955 return ret;
16956}
16957
16958DUK_EXTERNAL duk_uint16_t duk_to_uint16(duk_context *ctx, duk_idx_t index) {
16959 duk_hthread *thr = (duk_hthread *) ctx;
16960 duk_tval *tv;
7c673cae
FG
16961 duk_uint16_t ret;
16962
16963 DUK_ASSERT_CTX_VALID(ctx);
16964
16965 tv = duk_require_tval(ctx, index);
16966 DUK_ASSERT(tv != NULL);
16967 ret = duk_js_touint16(thr, tv);
16968
16969 /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
16970 tv = duk_require_tval(ctx, index);
11fdf7f2 16971 DUK_TVAL_SET_FASTINT_U32_UPDREF(thr, tv, ret); /* side effects */
7c673cae
FG
16972 return ret;
16973}
16974
16975#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
16976/* Special coercion for Uint8ClampedArray. */
16977DUK_INTERNAL duk_uint8_t duk_to_uint8clamped(duk_context *ctx, duk_idx_t index) {
16978 duk_double_t d;
16979 duk_double_t t;
16980 duk_uint8_t ret;
16981
16982 /* XXX: Simplify this algorithm, should be possible to come up with
16983 * a shorter and faster algorithm by inspecting IEEE representation
16984 * directly.
16985 */
16986
16987 d = duk_to_number(ctx, index);
16988 if (d <= 0.0) {
16989 return 0;
16990 } else if (d >= 255) {
16991 return 255;
16992 } else if (DUK_ISNAN(d)) {
16993 /* Avoid NaN-to-integer coercion as it is compiler specific. */
16994 return 0;
16995 }
16996
16997 t = d - DUK_FLOOR(d);
16998 if (t == 0.5) {
16999 /* Exact halfway, round to even. */
17000 ret = (duk_uint8_t) d;
17001 ret = (ret + 1) & 0xfe; /* Example: d=3.5, t=0.5 -> ret = (3 + 1) & 0xfe = 4 & 0xfe = 4
17002 * Example: d=4.5, t=0.5 -> ret = (4 + 1) & 0xfe = 5 & 0xfe = 4
17003 */
17004 } else {
17005 /* Not halfway, round to nearest. */
17006 ret = (duk_uint8_t) (d + 0.5);
17007 }
17008 return ret;
17009}
17010#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
17011
17012DUK_EXTERNAL const char *duk_to_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) {
17013 DUK_ASSERT_CTX_VALID(ctx);
17014
17015 (void) duk_to_string(ctx, index);
17016 return duk_require_lstring(ctx, index, out_len);
17017}
17018
17019DUK_LOCAL duk_ret_t duk__safe_to_string_raw(duk_context *ctx) {
17020 DUK_ASSERT_CTX_VALID(ctx);
17021
17022 duk_to_string(ctx, -1);
17023 return 1;
17024}
17025
17026DUK_EXTERNAL const char *duk_safe_to_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) {
17027 DUK_ASSERT_CTX_VALID(ctx);
17028
17029 index = duk_require_normalize_index(ctx, index);
17030
17031 /* We intentionally ignore the duk_safe_call() return value and only
17032 * check the output type. This way we don't also need to check that
17033 * the returned value is indeed a string in the success case.
17034 */
17035
17036 duk_dup(ctx, index);
17037 (void) duk_safe_call(ctx, duk__safe_to_string_raw, 1 /*nargs*/, 1 /*nrets*/);
17038 if (!duk_is_string(ctx, -1)) {
17039 /* Error: try coercing error to string once. */
17040 (void) duk_safe_call(ctx, duk__safe_to_string_raw, 1 /*nargs*/, 1 /*nrets*/);
17041 if (!duk_is_string(ctx, -1)) {
17042 /* Double error */
17043 duk_pop(ctx);
17044 duk_push_hstring_stridx(ctx, DUK_STRIDX_UC_ERROR);
17045 } else {
17046 ;
17047 }
17048 } else {
17049 ;
17050 }
17051 DUK_ASSERT(duk_is_string(ctx, -1));
11fdf7f2 17052 DUK_ASSERT(duk_get_string(ctx, -1) != NULL);
7c673cae
FG
17053
17054 duk_replace(ctx, index);
11fdf7f2
TL
17055 return duk_get_lstring(ctx, index, out_len);
17056}
17057
17058#if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */
17059DUK_INTERNAL duk_hstring *duk_safe_to_hstring(duk_context *ctx, duk_idx_t index) {
17060 (void) duk_safe_to_string(ctx, index);
17061 DUK_ASSERT(duk_is_string(ctx, index));
17062 DUK_ASSERT(duk_get_hstring(ctx, index) != NULL);
17063 return duk_get_hstring(ctx, index);
7c673cae 17064}
11fdf7f2
TL
17065#endif
17066
17067/* Coerce top into Object.prototype.toString() output. */
17068DUK_INTERNAL void duk_to_object_class_string_top(duk_context *ctx) {
17069 duk_hthread *thr;
17070 duk_uint_t typemask;
17071 duk_hstring *h_strclass;
17072
17073 DUK_ASSERT_CTX_VALID(ctx);
17074 thr = (duk_hthread *) ctx;
17075 DUK_UNREF(thr);
17076
17077 typemask = duk_get_type_mask(ctx, -1);
17078 if (typemask & DUK_TYPE_MASK_UNDEFINED) {
17079 h_strclass = DUK_HTHREAD_STRING_UC_UNDEFINED(thr);
17080 } else if (typemask & DUK_TYPE_MASK_NULL) {
17081 h_strclass = DUK_HTHREAD_STRING_UC_NULL(thr);
17082 } else {
17083 duk_hobject *h_obj;
17084
17085 duk_to_object(ctx, -1);
17086 h_obj = duk_get_hobject(ctx, -1);
17087 DUK_ASSERT(h_obj != NULL);
17088
17089 h_strclass = DUK_HOBJECT_GET_CLASS_STRING(thr->heap, h_obj);
17090 }
17091 DUK_ASSERT(h_strclass != NULL);
17092
17093 duk_pop(ctx);
17094 duk_push_sprintf(ctx, "[object %s]", (const char *) DUK_HSTRING_GET_DATA(h_strclass));
17095}
17096
17097#if !defined(DUK_USE_PARANOID_ERRORS)
17098DUK_INTERNAL void duk_push_hobject_class_string(duk_context *ctx, duk_hobject *h) {
17099 duk_hthread *thr;
17100 duk_hstring *h_strclass;
17101
17102 DUK_ASSERT_CTX_VALID(ctx);
17103 DUK_ASSERT(h != NULL);
17104 thr = (duk_hthread *) ctx;
17105 DUK_UNREF(thr);
17106
17107 h_strclass = DUK_HOBJECT_GET_CLASS_STRING(thr->heap, h);
17108 DUK_ASSERT(h_strclass != NULL);
17109 duk_push_sprintf(ctx, "[object %s]", (const char *) DUK_HSTRING_GET_DATA(h_strclass));
17110}
17111#endif /* !DUK_USE_PARANOID_ERRORS */
7c673cae
FG
17112
17113/* XXX: other variants like uint, u32 etc */
17114DUK_INTERNAL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped) {
17115 duk_hthread *thr = (duk_hthread *) ctx;
17116 duk_tval *tv;
17117 duk_tval tv_tmp;
17118 duk_double_t d, dmin, dmax;
17119 duk_int_t res;
17120 duk_bool_t clamped = 0;
17121
17122 DUK_ASSERT_CTX_VALID(ctx);
17123
17124 tv = duk_require_tval(ctx, index);
17125 DUK_ASSERT(tv != NULL);
17126 d = duk_js_tointeger(thr, tv); /* E5 Section 9.4, ToInteger() */
17127
17128 dmin = (duk_double_t) minval;
17129 dmax = (duk_double_t) maxval;
17130
17131 if (d < dmin) {
17132 clamped = 1;
17133 res = minval;
17134 d = dmin;
17135 } else if (d > dmax) {
17136 clamped = 1;
17137 res = maxval;
17138 d = dmax;
17139 } else {
17140 res = (duk_int_t) d;
17141 }
11fdf7f2 17142 DUK_UNREF(d); /* SCANBUILD: with suitable dmin/dmax limits 'd' is unused */
7c673cae
FG
17143 /* 'd' and 'res' agree here */
17144
17145 /* Relookup in case duk_js_tointeger() ends up e.g. coercing an object. */
11fdf7f2
TL
17146 tv = duk_get_tval(ctx, index);
17147 DUK_ASSERT(tv != NULL); /* not popped by side effect */
7c673cae
FG
17148 DUK_TVAL_SET_TVAL(&tv_tmp, tv);
17149#if defined(DUK_USE_FASTINT)
17150#if (DUK_INT_MAX <= 0x7fffffffL)
17151 DUK_TVAL_SET_FASTINT_I32(tv, res);
17152#else
17153 /* Clamping needed if duk_int_t is 64 bits. */
17154 if (res >= DUK_FASTINT_MIN && res <= DUK_FASTINT_MAX) {
17155 DUK_TVAL_SET_FASTINT(tv, res);
17156 } else {
17157 DUK_TVAL_SET_NUMBER(tv, d);
17158 }
17159#endif
17160#else
17161 DUK_TVAL_SET_NUMBER(tv, d); /* no need to incref */
17162#endif
17163 DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
17164
17165 if (out_clamped) {
17166 *out_clamped = clamped;
17167 } else {
17168 /* coerced value is updated to value stack even when RangeError thrown */
17169 if (clamped) {
11fdf7f2 17170 DUK_ERROR_RANGE(thr, DUK_STR_NUMBER_OUTSIDE_RANGE);
7c673cae
FG
17171 }
17172 }
17173
17174 return res;
17175}
17176
17177DUK_INTERNAL duk_int_t duk_to_int_clamped(duk_context *ctx, duk_idx_t index, duk_idx_t minval, duk_idx_t maxval) {
17178 duk_bool_t dummy;
17179 return duk_to_int_clamped_raw(ctx, index, minval, maxval, &dummy);
17180}
17181
17182DUK_INTERNAL duk_int_t duk_to_int_check_range(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval) {
17183 return duk_to_int_clamped_raw(ctx, index, minval, maxval, NULL); /* out_clamped==NULL -> RangeError if outside range */
17184}
17185
17186DUK_EXTERNAL const char *duk_to_string(duk_context *ctx, duk_idx_t index) {
17187 duk_hthread *thr = (duk_hthread *) ctx;
17188 duk_tval *tv;
17189
17190 DUK_ASSERT_CTX_VALID(ctx);
17191 DUK_UNREF(thr);
17192
17193 index = duk_require_normalize_index(ctx, index);
17194
17195 tv = duk_require_tval(ctx, index);
17196 DUK_ASSERT(tv != NULL);
17197
17198 switch (DUK_TVAL_GET_TAG(tv)) {
17199 case DUK_TAG_UNDEFINED: {
17200 duk_push_hstring_stridx(ctx, DUK_STRIDX_LC_UNDEFINED);
17201 break;
17202 }
17203 case DUK_TAG_NULL: {
17204 duk_push_hstring_stridx(ctx, DUK_STRIDX_LC_NULL);
17205 break;
17206 }
17207 case DUK_TAG_BOOLEAN: {
17208 if (DUK_TVAL_GET_BOOLEAN(tv)) {
17209 duk_push_hstring_stridx(ctx, DUK_STRIDX_TRUE);
17210 } else {
17211 duk_push_hstring_stridx(ctx, DUK_STRIDX_FALSE);
17212 }
17213 break;
17214 }
17215 case DUK_TAG_STRING: {
17216 /* nop */
17217 goto skip_replace;
17218 }
17219 case DUK_TAG_OBJECT: {
17220 duk_to_primitive(ctx, index, DUK_HINT_STRING);
17221 return duk_to_string(ctx, index); /* Note: recursive call */
17222 }
17223 case DUK_TAG_BUFFER: {
17224 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
17225
17226 /* Note: this allows creation of internal strings. */
17227
17228 DUK_ASSERT(h != NULL);
17229 duk_push_lstring(ctx,
17230 (const char *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h),
17231 (duk_size_t) DUK_HBUFFER_GET_SIZE(h));
17232 break;
17233 }
17234 case DUK_TAG_POINTER: {
17235 void *ptr = DUK_TVAL_GET_POINTER(tv);
17236 if (ptr != NULL) {
17237 duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) ptr);
17238 } else {
17239 /* Represent a null pointer as 'null' to be consistent with
17240 * the JX format variant. Native '%p' format for a NULL
17241 * pointer may be e.g. '(nil)'.
17242 */
17243 duk_push_hstring_stridx(ctx, DUK_STRIDX_LC_NULL);
17244 }
17245 break;
17246 }
17247 case DUK_TAG_LIGHTFUNC: {
17248 /* Should match Function.prototype.toString() */
17249 duk_push_lightfunc_tostring(ctx, tv);
17250 break;
17251 }
17252#if defined(DUK_USE_FASTINT)
17253 case DUK_TAG_FASTINT:
17254#endif
17255 default: {
17256 /* number */
11fdf7f2 17257 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
7c673cae
FG
17258 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
17259 duk_push_tval(ctx, tv);
17260 duk_numconv_stringify(ctx,
17261 10 /*radix*/,
17262 0 /*precision:shortest*/,
17263 0 /*force_exponential*/);
17264 break;
17265 }
17266 }
17267
17268 duk_replace(ctx, index);
17269
17270 skip_replace:
17271 return duk_require_string(ctx, index);
17272}
17273
17274DUK_INTERNAL duk_hstring *duk_to_hstring(duk_context *ctx, duk_idx_t index) {
17275 duk_hstring *ret;
17276 DUK_ASSERT_CTX_VALID(ctx);
17277 duk_to_string(ctx, index);
17278 ret = duk_get_hstring(ctx, index);
17279 DUK_ASSERT(ret != NULL);
17280 return ret;
17281}
17282
17283DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t index, duk_size_t *out_size, duk_uint_t mode) {
17284 duk_hthread *thr = (duk_hthread *) ctx;
17285 duk_hbuffer *h_buf;
17286 const duk_uint8_t *src_data;
17287 duk_size_t src_size;
17288 duk_uint8_t *dst_data;
17289
17290 DUK_ASSERT_CTX_VALID(ctx);
17291 DUK_UNREF(thr);
17292
17293 index = duk_require_normalize_index(ctx, index);
17294
17295 h_buf = duk_get_hbuffer(ctx, index);
17296 if (h_buf != NULL) {
17297 /* Buffer is kept as is, with the fixed/dynamic nature of the
17298 * buffer only changed if requested. An external buffer
17299 * is converted into a non-external dynamic buffer in a
17300 * duk_to_dynamic_buffer() call.
17301 */
17302 duk_uint_t tmp;
11fdf7f2 17303 duk_uint8_t *tmp_ptr;
7c673cae 17304
11fdf7f2
TL
17305 tmp_ptr = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_buf);
17306 src_data = (const duk_uint8_t *) tmp_ptr;
7c673cae
FG
17307 src_size = DUK_HBUFFER_GET_SIZE(h_buf);
17308
17309 tmp = (DUK_HBUFFER_HAS_DYNAMIC(h_buf) ? DUK_BUF_MODE_DYNAMIC : DUK_BUF_MODE_FIXED);
17310 if ((tmp == mode && !DUK_HBUFFER_HAS_EXTERNAL(h_buf)) ||
17311 mode == DUK_BUF_MODE_DONTCARE) {
17312 /* Note: src_data may be NULL if input is a zero-size
17313 * dynamic buffer.
17314 */
11fdf7f2 17315 dst_data = tmp_ptr;
7c673cae
FG
17316 goto skip_copy;
17317 }
17318 } else {
17319 /* Non-buffer value is first ToString() coerced, then converted
17320 * to a buffer (fixed buffer is used unless a dynamic buffer is
17321 * explicitly requested).
17322 */
17323
17324 src_data = (const duk_uint8_t *) duk_to_lstring(ctx, index, &src_size);
17325 }
17326
17327 dst_data = (duk_uint8_t *) duk_push_buffer(ctx, src_size, (mode == DUK_BUF_MODE_DYNAMIC) /*dynamic*/);
17328 if (DUK_LIKELY(src_size > 0)) {
17329 /* When src_size == 0, src_data may be NULL (if source
17330 * buffer is dynamic), and dst_data may be NULL (if
17331 * target buffer is dynamic). Avoid zero-size memcpy()
17332 * with an invalid pointer.
17333 */
11fdf7f2 17334 DUK_MEMCPY((void *) dst_data, (const void *) src_data, (size_t) src_size);
7c673cae
FG
17335 }
17336 duk_replace(ctx, index);
17337 skip_copy:
17338
17339 if (out_size) {
17340 *out_size = src_size;
17341 }
17342 return dst_data;
17343}
17344
17345DUK_EXTERNAL void *duk_to_pointer(duk_context *ctx, duk_idx_t index) {
17346 duk_tval *tv;
17347 void *res;
17348
17349 DUK_ASSERT_CTX_VALID(ctx);
17350
17351 index = duk_require_normalize_index(ctx, index);
17352
17353 tv = duk_require_tval(ctx, index);
17354 DUK_ASSERT(tv != NULL);
17355
17356 switch (DUK_TVAL_GET_TAG(tv)) {
17357 case DUK_TAG_UNDEFINED:
17358 case DUK_TAG_NULL:
17359 case DUK_TAG_BOOLEAN:
17360 res = NULL;
17361 break;
17362 case DUK_TAG_POINTER:
17363 res = DUK_TVAL_GET_POINTER(tv);
17364 break;
17365 case DUK_TAG_STRING:
17366 case DUK_TAG_OBJECT:
17367 case DUK_TAG_BUFFER:
17368 /* Heap allocated: return heap pointer which is NOT useful
17369 * for the caller, except for debugging.
17370 */
17371 res = (void *) DUK_TVAL_GET_HEAPHDR(tv);
17372 break;
17373 case DUK_TAG_LIGHTFUNC:
17374 /* Function pointers do not always cast correctly to void *
17375 * (depends on memory and segmentation model for instance),
17376 * so they coerce to NULL.
17377 */
17378 res = NULL;
17379 break;
17380#if defined(DUK_USE_FASTINT)
17381 case DUK_TAG_FASTINT:
17382#endif
17383 default:
17384 /* number */
11fdf7f2
TL
17385 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
17386 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
7c673cae
FG
17387 res = NULL;
17388 break;
17389 }
17390
17391 duk_push_pointer(ctx, res);
17392 duk_replace(ctx, index);
17393 return res;
17394}
17395
17396DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t index) {
17397 duk_hthread *thr = (duk_hthread *) ctx;
17398 duk_tval *tv;
17399 duk_uint_t flags = 0; /* shared flags for a subset of types */
17400 duk_small_int_t proto = 0;
17401
17402 DUK_ASSERT_CTX_VALID(ctx);
17403
17404 index = duk_require_normalize_index(ctx, index);
17405
17406 tv = duk_require_tval(ctx, index);
17407 DUK_ASSERT(tv != NULL);
17408
17409 switch (DUK_TVAL_GET_TAG(tv)) {
17410 case DUK_TAG_UNDEFINED:
17411 case DUK_TAG_NULL: {
11fdf7f2 17412 DUK_ERROR_TYPE(thr, DUK_STR_NOT_OBJECT_COERCIBLE);
7c673cae
FG
17413 break;
17414 }
17415 case DUK_TAG_BOOLEAN: {
17416 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
17417 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BOOLEAN);
17418 proto = DUK_BIDX_BOOLEAN_PROTOTYPE;
17419 goto create_object;
17420 }
17421 case DUK_TAG_STRING: {
17422 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
17423 DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ |
17424 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING);
17425 proto = DUK_BIDX_STRING_PROTOTYPE;
17426 goto create_object;
17427 }
17428 case DUK_TAG_OBJECT: {
17429 /* nop */
17430 break;
17431 }
17432 case DUK_TAG_BUFFER: {
17433 /* A plain buffer coerces to a Duktape.Buffer because it's the
17434 * object counterpart of the plain buffer value. But it might
17435 * still make more sense to produce an ArrayBuffer here?
17436 */
17437
17438 duk_hbufferobject *h_bufobj;
17439 duk_hbuffer *h_val;
17440
17441 h_val = DUK_TVAL_GET_BUFFER(tv);
17442 DUK_ASSERT(h_val != NULL);
17443
17444 h_bufobj = duk_push_bufferobject_raw(ctx,
17445 DUK_HOBJECT_FLAG_EXTENSIBLE |
17446 DUK_HOBJECT_FLAG_BUFFEROBJECT |
17447 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER),
17448 DUK_BIDX_BUFFER_PROTOTYPE);
17449 DUK_ASSERT(h_bufobj != NULL);
17450 DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE((duk_hobject *) h_bufobj));
17451 DUK_ASSERT(DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) h_bufobj));
17452
17453 h_bufobj->buf = h_val;
17454 DUK_HBUFFER_INCREF(thr, h_val);
17455 DUK_ASSERT(h_bufobj->offset == 0);
17456 h_bufobj->length = (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_val);
17457 DUK_ASSERT(h_bufobj->shift == 0);
17458 DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8);
17459
17460 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
17461 goto replace_value;
17462 }
17463 case DUK_TAG_POINTER: {
17464 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
17465 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER);
17466 proto = DUK_BIDX_POINTER_PROTOTYPE;
17467 goto create_object;
17468 }
17469 case DUK_TAG_LIGHTFUNC: {
17470 /* Lightfunc coerces to a Function instance with concrete
17471 * properties. Since 'length' is virtual for Duktape/C
17472 * functions, don't need to define that.
17473 *
17474 * The result is made extensible to mimic what happens to
17475 * strings:
17476 * > Object.isExtensible(Object('foo'))
17477 * true
17478 */
17479 duk_small_uint_t lf_flags;
11fdf7f2 17480 duk_idx_t nargs;
7c673cae
FG
17481 duk_small_uint_t lf_len;
17482 duk_c_function func;
17483 duk_hnativefunction *nf;
17484
17485 DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags);
17486
11fdf7f2 17487 nargs = (duk_idx_t) DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
7c673cae 17488 if (nargs == DUK_LFUNC_NARGS_VARARGS) {
11fdf7f2 17489 nargs = (duk_idx_t) DUK_VARARGS;
7c673cae
FG
17490 }
17491 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
17492 DUK_HOBJECT_FLAG_CONSTRUCTABLE |
17493 DUK_HOBJECT_FLAG_NATIVEFUNCTION |
17494 DUK_HOBJECT_FLAG_NEWENV |
17495 DUK_HOBJECT_FLAG_STRICT |
17496 DUK_HOBJECT_FLAG_NOTAIL |
17497 /* DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC: omitted here intentionally */
17498 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
11fdf7f2 17499 (void) duk__push_c_function_raw(ctx, func, nargs, flags);
7c673cae
FG
17500
17501 lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
11fdf7f2 17502 if ((duk_idx_t) lf_len != nargs) {
7c673cae
FG
17503 /* Explicit length is only needed if it differs from 'nargs'. */
17504 duk_push_int(ctx, (duk_int_t) lf_len);
17505 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
17506 }
17507 duk_push_lightfunc_name(ctx, tv);
17508 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
17509
17510 nf = duk_get_hnativefunction(ctx, -1);
17511 DUK_ASSERT(nf != NULL);
17512 nf->magic = (duk_int16_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags);
17513
17514 /* Enable DUKFUNC exotic behavior once properties are set up. */
17515 DUK_HOBJECT_SET_EXOTIC_DUKFUNC((duk_hobject *) nf);
17516 goto replace_value;
17517 }
17518#if defined(DUK_USE_FASTINT)
17519 case DUK_TAG_FASTINT:
17520#endif
17521 default: {
11fdf7f2
TL
17522 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
17523 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
7c673cae
FG
17524 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
17525 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_NUMBER);
17526 proto = DUK_BIDX_NUMBER_PROTOTYPE;
17527 goto create_object;
17528 }
17529 }
17530 return;
17531
17532 create_object:
17533 (void) duk_push_object_helper(ctx, flags, proto);
17534
17535 /* Note: Boolean prototype's internal value property is not writable,
17536 * but duk_xdef_prop_stridx() disregards the write protection. Boolean
17537 * instances are immutable.
17538 *
17539 * String and buffer special behaviors are already enabled which is not
17540 * ideal, but a write to the internal value is not affected by them.
17541 */
17542 duk_dup(ctx, index);
17543 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
17544
17545 replace_value:
17546 duk_replace(ctx, index);
17547}
17548
17549/*
17550 * Type checking
17551 */
17552
17553DUK_LOCAL duk_bool_t duk__tag_check(duk_context *ctx, duk_idx_t index, duk_small_uint_t tag) {
17554 duk_tval *tv;
17555
17556 tv = duk_get_tval(ctx, index);
17557 if (!tv) {
17558 return 0;
17559 }
17560 return (DUK_TVAL_GET_TAG(tv) == tag);
17561}
17562
17563DUK_LOCAL duk_bool_t duk__obj_flag_any_default_false(duk_context *ctx, duk_idx_t index, duk_uint_t flag_mask) {
17564 duk_hobject *obj;
17565
17566 DUK_ASSERT_CTX_VALID(ctx);
17567
17568 obj = duk_get_hobject(ctx, index);
17569 if (obj) {
17570 return (DUK_HEAPHDR_CHECK_FLAG_BITS((duk_heaphdr *) obj, flag_mask) ? 1 : 0);
17571 }
17572 return 0;
17573}
17574
17575DUK_EXTERNAL duk_int_t duk_get_type(duk_context *ctx, duk_idx_t index) {
17576 duk_tval *tv;
17577
17578 DUK_ASSERT_CTX_VALID(ctx);
17579
17580 tv = duk_get_tval(ctx, index);
17581 if (!tv) {
17582 return DUK_TYPE_NONE;
17583 }
17584 switch (DUK_TVAL_GET_TAG(tv)) {
17585 case DUK_TAG_UNDEFINED:
17586 return DUK_TYPE_UNDEFINED;
17587 case DUK_TAG_NULL:
17588 return DUK_TYPE_NULL;
17589 case DUK_TAG_BOOLEAN:
17590 return DUK_TYPE_BOOLEAN;
17591 case DUK_TAG_STRING:
17592 return DUK_TYPE_STRING;
17593 case DUK_TAG_OBJECT:
17594 return DUK_TYPE_OBJECT;
17595 case DUK_TAG_BUFFER:
17596 return DUK_TYPE_BUFFER;
17597 case DUK_TAG_POINTER:
17598 return DUK_TYPE_POINTER;
17599 case DUK_TAG_LIGHTFUNC:
17600 return DUK_TYPE_LIGHTFUNC;
17601#if defined(DUK_USE_FASTINT)
17602 case DUK_TAG_FASTINT:
17603#endif
17604 default:
17605 /* Note: number has no explicit tag (in 8-byte representation) */
11fdf7f2 17606 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
7c673cae
FG
17607 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
17608 return DUK_TYPE_NUMBER;
17609 }
17610 DUK_UNREACHABLE();
17611}
17612
11fdf7f2
TL
17613#if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS)
17614DUK_LOCAL const char *duk__type_names[] = {
17615 "none",
17616 "undefined",
17617 "null",
17618 "boolean",
17619 "number",
17620 "string",
17621 "object",
17622 "buffer",
17623 "pointer",
17624 "lightfunc"
17625};
17626
17627DUK_INTERNAL const char *duk_get_type_name(duk_context *ctx, duk_idx_t index) {
17628 duk_int_t type_tag;
17629
17630 type_tag = duk_get_type(ctx, index);
17631 DUK_ASSERT(type_tag >= DUK_TYPE_MIN && type_tag <= DUK_TYPE_MAX);
17632 DUK_ASSERT(DUK_TYPE_MIN == 0 && sizeof(duk__type_names) / sizeof(const char *) == DUK_TYPE_MAX + 1);
17633
17634 return duk__type_names[type_tag];
17635}
17636#endif
17637
7c673cae
FG
17638DUK_EXTERNAL duk_bool_t duk_check_type(duk_context *ctx, duk_idx_t index, duk_int_t type) {
17639 DUK_ASSERT_CTX_VALID(ctx);
17640
17641 return (duk_get_type(ctx, index) == type) ? 1 : 0;
17642}
17643
17644DUK_EXTERNAL duk_uint_t duk_get_type_mask(duk_context *ctx, duk_idx_t index) {
17645 duk_tval *tv;
17646
17647 DUK_ASSERT_CTX_VALID(ctx);
17648
17649 tv = duk_get_tval(ctx, index);
17650 if (!tv) {
17651 return DUK_TYPE_MASK_NONE;
17652 }
17653 switch (DUK_TVAL_GET_TAG(tv)) {
17654 case DUK_TAG_UNDEFINED:
17655 return DUK_TYPE_MASK_UNDEFINED;
17656 case DUK_TAG_NULL:
17657 return DUK_TYPE_MASK_NULL;
17658 case DUK_TAG_BOOLEAN:
17659 return DUK_TYPE_MASK_BOOLEAN;
17660 case DUK_TAG_STRING:
17661 return DUK_TYPE_MASK_STRING;
17662 case DUK_TAG_OBJECT:
17663 return DUK_TYPE_MASK_OBJECT;
17664 case DUK_TAG_BUFFER:
17665 return DUK_TYPE_MASK_BUFFER;
17666 case DUK_TAG_POINTER:
17667 return DUK_TYPE_MASK_POINTER;
17668 case DUK_TAG_LIGHTFUNC:
17669 return DUK_TYPE_MASK_LIGHTFUNC;
17670#if defined(DUK_USE_FASTINT)
17671 case DUK_TAG_FASTINT:
17672#endif
17673 default:
17674 /* Note: number has no explicit tag (in 8-byte representation) */
11fdf7f2 17675 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
7c673cae
FG
17676 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
17677 return DUK_TYPE_MASK_NUMBER;
17678 }
17679 DUK_UNREACHABLE();
17680}
17681
17682DUK_EXTERNAL duk_bool_t duk_check_type_mask(duk_context *ctx, duk_idx_t index, duk_uint_t mask) {
17683 duk_hthread *thr = (duk_hthread *) ctx;
17684
17685 DUK_ASSERT_CTX_VALID(ctx);
17686
17687 if (duk_get_type_mask(ctx, index) & mask) {
17688 return 1;
17689 }
17690 if (mask & DUK_TYPE_MASK_THROW) {
11fdf7f2 17691 DUK_ERROR_TYPE(thr, DUK_STR_UNEXPECTED_TYPE);
7c673cae
FG
17692 DUK_UNREACHABLE();
17693 }
17694 return 0;
17695}
17696
17697DUK_EXTERNAL duk_bool_t duk_is_undefined(duk_context *ctx, duk_idx_t index) {
17698 DUK_ASSERT_CTX_VALID(ctx);
17699 return duk__tag_check(ctx, index, DUK_TAG_UNDEFINED);
17700}
17701
17702DUK_EXTERNAL duk_bool_t duk_is_null(duk_context *ctx, duk_idx_t index) {
17703 DUK_ASSERT_CTX_VALID(ctx);
17704 return duk__tag_check(ctx, index, DUK_TAG_NULL);
17705}
17706
17707DUK_EXTERNAL duk_bool_t duk_is_null_or_undefined(duk_context *ctx, duk_idx_t index) {
17708 duk_tval *tv;
17709 duk_small_uint_t tag;
17710
17711 DUK_ASSERT_CTX_VALID(ctx);
17712
17713 tv = duk_get_tval(ctx, index);
17714 if (!tv) {
17715 return 0;
17716 }
17717 tag = DUK_TVAL_GET_TAG(tv);
17718 return (tag == DUK_TAG_UNDEFINED) || (tag == DUK_TAG_NULL);
17719}
17720
17721DUK_EXTERNAL duk_bool_t duk_is_boolean(duk_context *ctx, duk_idx_t index) {
17722 DUK_ASSERT_CTX_VALID(ctx);
17723 return duk__tag_check(ctx, index, DUK_TAG_BOOLEAN);
17724}
17725
17726DUK_EXTERNAL duk_bool_t duk_is_number(duk_context *ctx, duk_idx_t index) {
17727 duk_tval *tv;
17728
17729 DUK_ASSERT_CTX_VALID(ctx);
17730
17731 /*
17732 * Number is special because it doesn't have a specific
17733 * tag in the 8-byte representation.
17734 */
17735
17736 /* XXX: shorter version for 12-byte representation? */
17737
17738 tv = duk_get_tval(ctx, index);
17739 if (!tv) {
17740 return 0;
17741 }
17742 return DUK_TVAL_IS_NUMBER(tv);
17743}
17744
17745DUK_EXTERNAL duk_bool_t duk_is_nan(duk_context *ctx, duk_idx_t index) {
17746 /* XXX: This will now return false for non-numbers, even though they would
17747 * coerce to NaN (as a general rule). In particular, duk_get_number()
17748 * returns a NaN for non-numbers, so should this function also return
17749 * true for non-numbers?
17750 */
17751
17752 duk_tval *tv;
17753
17754 DUK_ASSERT_CTX_VALID(ctx);
17755
17756 tv = duk_get_tval(ctx, index);
17757 if (!tv || !DUK_TVAL_IS_NUMBER(tv)) {
17758 return 0;
17759 }
17760 return DUK_ISNAN(DUK_TVAL_GET_NUMBER(tv));
17761}
17762
17763DUK_EXTERNAL duk_bool_t duk_is_string(duk_context *ctx, duk_idx_t index) {
17764 DUK_ASSERT_CTX_VALID(ctx);
17765 return duk__tag_check(ctx, index, DUK_TAG_STRING);
17766}
17767
17768DUK_EXTERNAL duk_bool_t duk_is_object(duk_context *ctx, duk_idx_t index) {
17769 DUK_ASSERT_CTX_VALID(ctx);
17770 return duk__tag_check(ctx, index, DUK_TAG_OBJECT);
17771}
17772
17773DUK_EXTERNAL duk_bool_t duk_is_buffer(duk_context *ctx, duk_idx_t index) {
17774 DUK_ASSERT_CTX_VALID(ctx);
17775 return duk__tag_check(ctx, index, DUK_TAG_BUFFER);
17776}
17777
11fdf7f2
TL
17778#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
17779DUK_EXTERNAL duk_bool_t duk_is_buffer_data(duk_context *ctx, duk_idx_t idx) {
17780 duk_tval *tv;
17781
17782 DUK_ASSERT_CTX_VALID(ctx);
17783
17784 tv = duk_get_tval(ctx, idx);
17785 if (tv == NULL) {
17786 return 0;
17787 }
17788 if (DUK_TVAL_IS_BUFFER(tv)) {
17789 return 1;
17790 } else if (DUK_TVAL_IS_OBJECT(tv)) {
17791 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
17792 DUK_ASSERT(h != NULL);
17793 if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
17794 return 1;
17795 }
17796 }
17797 return 0;
17798}
17799#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
17800DUK_EXTERNAL duk_bool_t duk_is_buffer_data(duk_context *ctx, duk_idx_t idx) {
17801 DUK_ASSERT_CTX_VALID(ctx);
17802
17803 return duk_is_buffer(ctx, idx);
17804}
17805#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
17806
7c673cae
FG
17807DUK_EXTERNAL duk_bool_t duk_is_pointer(duk_context *ctx, duk_idx_t index) {
17808 DUK_ASSERT_CTX_VALID(ctx);
17809 return duk__tag_check(ctx, index, DUK_TAG_POINTER);
17810}
17811
17812DUK_EXTERNAL duk_bool_t duk_is_lightfunc(duk_context *ctx, duk_idx_t index) {
17813 DUK_ASSERT_CTX_VALID(ctx);
17814 return duk__tag_check(ctx, index, DUK_TAG_LIGHTFUNC);
17815}
17816
17817DUK_EXTERNAL duk_bool_t duk_is_array(duk_context *ctx, duk_idx_t index) {
17818 duk_hobject *obj;
17819
17820 DUK_ASSERT_CTX_VALID(ctx);
17821
17822 obj = duk_get_hobject(ctx, index);
17823 if (obj) {
17824 return (DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_ARRAY ? 1 : 0);
17825 }
17826 return 0;
17827}
17828
17829DUK_EXTERNAL duk_bool_t duk_is_function(duk_context *ctx, duk_idx_t index) {
17830 duk_tval *tv;
17831
17832 DUK_ASSERT_CTX_VALID(ctx);
17833
17834 tv = duk_get_tval(ctx, index);
17835 if (tv && DUK_TVAL_IS_LIGHTFUNC(tv)) {
17836 return 1;
17837 }
17838 return duk__obj_flag_any_default_false(ctx,
17839 index,
17840 DUK_HOBJECT_FLAG_COMPILEDFUNCTION |
17841 DUK_HOBJECT_FLAG_NATIVEFUNCTION |
17842 DUK_HOBJECT_FLAG_BOUND);
17843}
17844
17845DUK_EXTERNAL duk_bool_t duk_is_c_function(duk_context *ctx, duk_idx_t index) {
17846 DUK_ASSERT_CTX_VALID(ctx);
17847 return duk__obj_flag_any_default_false(ctx,
17848 index,
17849 DUK_HOBJECT_FLAG_NATIVEFUNCTION);
17850}
17851
17852DUK_EXTERNAL duk_bool_t duk_is_ecmascript_function(duk_context *ctx, duk_idx_t index) {
17853 DUK_ASSERT_CTX_VALID(ctx);
17854 return duk__obj_flag_any_default_false(ctx,
17855 index,
17856 DUK_HOBJECT_FLAG_COMPILEDFUNCTION);
17857}
17858
17859DUK_EXTERNAL duk_bool_t duk_is_bound_function(duk_context *ctx, duk_idx_t index) {
17860 DUK_ASSERT_CTX_VALID(ctx);
17861 return duk__obj_flag_any_default_false(ctx,
17862 index,
17863 DUK_HOBJECT_FLAG_BOUND);
17864}
17865
17866DUK_EXTERNAL duk_bool_t duk_is_thread(duk_context *ctx, duk_idx_t index) {
17867 DUK_ASSERT_CTX_VALID(ctx);
17868 return duk__obj_flag_any_default_false(ctx,
17869 index,
17870 DUK_HOBJECT_FLAG_THREAD);
17871}
17872
7c673cae
FG
17873DUK_EXTERNAL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t index) {
17874 duk_tval *tv;
17875
17876 DUK_ASSERT_CTX_VALID(ctx);
17877
17878 tv = duk_get_tval(ctx, index);
17879 if (tv && DUK_TVAL_IS_BUFFER(tv)) {
17880 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
17881 DUK_ASSERT(h != NULL);
17882 return (DUK_HBUFFER_HAS_DYNAMIC(h) ? 0 : 1);
17883 }
17884 return 0;
17885}
17886
17887DUK_EXTERNAL duk_bool_t duk_is_dynamic_buffer(duk_context *ctx, duk_idx_t index) {
17888 duk_tval *tv;
17889
17890 DUK_ASSERT_CTX_VALID(ctx);
17891
17892 tv = duk_get_tval(ctx, index);
17893 if (tv && DUK_TVAL_IS_BUFFER(tv)) {
17894 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
17895 DUK_ASSERT(h != NULL);
17896 return (DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h) ? 1 : 0);
17897 }
17898 return 0;
17899}
17900
17901DUK_EXTERNAL duk_bool_t duk_is_external_buffer(duk_context *ctx, duk_idx_t index) {
17902 duk_tval *tv;
17903
17904 DUK_ASSERT_CTX_VALID(ctx);
17905
17906 tv = duk_get_tval(ctx, index);
17907 if (tv && DUK_TVAL_IS_BUFFER(tv)) {
17908 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
17909 DUK_ASSERT(h != NULL);
17910 return (DUK_HBUFFER_HAS_DYNAMIC(h) && DUK_HBUFFER_HAS_EXTERNAL(h) ? 1 : 0);
17911 }
17912 return 0;
17913}
17914
17915DUK_EXTERNAL duk_errcode_t duk_get_error_code(duk_context *ctx, duk_idx_t index) {
17916 duk_hthread *thr = (duk_hthread *) ctx;
17917 duk_hobject *h;
17918 duk_uint_t sanity;
17919
17920 DUK_ASSERT_CTX_VALID(ctx);
17921
17922 h = duk_get_hobject(ctx, index);
17923
17924 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
17925 do {
17926 if (!h) {
17927 return DUK_ERR_NONE;
17928 }
17929 if (h == thr->builtins[DUK_BIDX_EVAL_ERROR_PROTOTYPE]) {
17930 return DUK_ERR_EVAL_ERROR;
17931 }
17932 if (h == thr->builtins[DUK_BIDX_RANGE_ERROR_PROTOTYPE]) {
17933 return DUK_ERR_RANGE_ERROR;
17934 }
17935 if (h == thr->builtins[DUK_BIDX_REFERENCE_ERROR_PROTOTYPE]) {
17936 return DUK_ERR_REFERENCE_ERROR;
17937 }
17938 if (h == thr->builtins[DUK_BIDX_SYNTAX_ERROR_PROTOTYPE]) {
17939 return DUK_ERR_SYNTAX_ERROR;
17940 }
17941 if (h == thr->builtins[DUK_BIDX_TYPE_ERROR_PROTOTYPE]) {
17942 return DUK_ERR_TYPE_ERROR;
17943 }
17944 if (h == thr->builtins[DUK_BIDX_URI_ERROR_PROTOTYPE]) {
17945 return DUK_ERR_URI_ERROR;
17946 }
17947 if (h == thr->builtins[DUK_BIDX_ERROR_PROTOTYPE]) {
17948 return DUK_ERR_ERROR;
17949 }
17950
17951 h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
17952 } while (--sanity > 0);
17953
17954 return DUK_ERR_NONE;
17955}
17956
17957/*
17958 * Pushers
17959 */
17960
17961DUK_INTERNAL void duk_push_tval(duk_context *ctx, duk_tval *tv) {
17962 duk_hthread *thr;
17963 duk_tval *tv_slot;
17964
17965 DUK_ASSERT_CTX_VALID(ctx);
17966 DUK_ASSERT(tv != NULL);
17967 thr = (duk_hthread *) ctx;
17968 DUK__CHECK_SPACE();
17969 tv_slot = thr->valstack_top++;
17970 DUK_TVAL_SET_TVAL(tv_slot, tv);
17971 DUK_TVAL_INCREF(thr, tv); /* no side effects */
17972}
17973
7c673cae
FG
17974DUK_EXTERNAL void duk_push_undefined(duk_context *ctx) {
17975 duk_hthread *thr;
7c673cae
FG
17976
17977 DUK_ASSERT_CTX_VALID(ctx);
17978 thr = (duk_hthread *) ctx;
17979 DUK__CHECK_SPACE();
11fdf7f2
TL
17980
17981 /* Because value stack init policy is 'undefined above top',
17982 * we don't need to write, just assert.
17983 */
17984 thr->valstack_top++;
17985 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 1));
7c673cae
FG
17986}
17987
17988DUK_EXTERNAL void duk_push_null(duk_context *ctx) {
17989 duk_hthread *thr;
17990 duk_tval *tv_slot;
17991
17992 DUK_ASSERT_CTX_VALID(ctx);
17993 thr = (duk_hthread *) ctx;
17994 DUK__CHECK_SPACE();
17995 tv_slot = thr->valstack_top++;
17996 DUK_TVAL_SET_NULL(tv_slot);
17997}
17998
17999DUK_EXTERNAL void duk_push_boolean(duk_context *ctx, duk_bool_t val) {
18000 duk_hthread *thr;
18001 duk_tval *tv_slot;
18002 duk_small_int_t b;
18003
18004 DUK_ASSERT_CTX_VALID(ctx);
18005 thr = (duk_hthread *) ctx;
18006 DUK__CHECK_SPACE();
18007 b = (val ? 1 : 0); /* ensure value is 1 or 0 (not other non-zero) */
18008 tv_slot = thr->valstack_top++;
18009 DUK_TVAL_SET_BOOLEAN(tv_slot, b);
18010}
18011
18012DUK_EXTERNAL void duk_push_true(duk_context *ctx) {
18013 duk_hthread *thr;
18014 duk_tval *tv_slot;
18015
18016 DUK_ASSERT_CTX_VALID(ctx);
18017 thr = (duk_hthread *) ctx;
18018 DUK__CHECK_SPACE();
18019 tv_slot = thr->valstack_top++;
18020 DUK_TVAL_SET_BOOLEAN_TRUE(tv_slot);
18021}
18022
18023DUK_EXTERNAL void duk_push_false(duk_context *ctx) {
18024 duk_hthread *thr;
18025 duk_tval *tv_slot;
18026
18027 DUK_ASSERT_CTX_VALID(ctx);
18028 thr = (duk_hthread *) ctx;
18029 DUK__CHECK_SPACE();
18030 tv_slot = thr->valstack_top++;
18031 DUK_TVAL_SET_BOOLEAN_FALSE(tv_slot);
18032}
18033
18034/* normalize NaN which may not match our canonical internal NaN */
18035DUK_EXTERNAL void duk_push_number(duk_context *ctx, duk_double_t val) {
18036 duk_hthread *thr;
18037 duk_tval *tv_slot;
18038 duk_double_union du;
18039
18040 DUK_ASSERT_CTX_VALID(ctx);
18041 thr = (duk_hthread *) ctx;
18042 DUK__CHECK_SPACE();
18043 du.d = val;
18044 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
18045 tv_slot = thr->valstack_top++;
18046 DUK_TVAL_SET_NUMBER(tv_slot, du.d);
18047}
18048
18049DUK_EXTERNAL void duk_push_int(duk_context *ctx, duk_int_t val) {
18050#if defined(DUK_USE_FASTINT)
18051 duk_hthread *thr;
18052 duk_tval *tv_slot;
18053
18054 DUK_ASSERT_CTX_VALID(ctx);
18055 thr = (duk_hthread *) ctx;
18056 DUK__CHECK_SPACE();
18057 tv_slot = thr->valstack_top++;
18058#if DUK_INT_MAX <= 0x7fffffffL
18059 DUK_TVAL_SET_FASTINT_I32(tv_slot, (duk_int32_t) val);
18060#else
18061 if (val >= DUK_FASTINT_MIN && val <= DUK_FASTINT_MAX) {
18062 DUK_TVAL_SET_FASTINT(tv_slot, (duk_int64_t) val);
18063 } else {
18064 duk_double_t = (duk_double_t) val;
18065 DUK_TVAL_SET_NUMBER(tv_slot, d);
18066 }
18067#endif
18068#else /* DUK_USE_FASTINT */
18069 duk_hthread *thr;
18070 duk_tval *tv_slot;
18071 duk_double_t d;
18072
18073 DUK_ASSERT_CTX_VALID(ctx);
18074 thr = (duk_hthread *) ctx;
18075 DUK__CHECK_SPACE();
18076 d = (duk_double_t) val;
18077 tv_slot = thr->valstack_top++;
18078 DUK_TVAL_SET_NUMBER(tv_slot, d);
18079#endif /* DUK_USE_FASTINT */
18080}
18081
18082DUK_EXTERNAL void duk_push_uint(duk_context *ctx, duk_uint_t val) {
18083#if defined(DUK_USE_FASTINT)
18084 duk_hthread *thr;
18085 duk_tval *tv_slot;
18086
18087 DUK_ASSERT_CTX_VALID(ctx);
18088 thr = (duk_hthread *) ctx;
18089 DUK__CHECK_SPACE();
18090 tv_slot = thr->valstack_top++;
18091#if DUK_UINT_MAX <= 0xffffffffUL
18092 DUK_TVAL_SET_FASTINT_U32(tv_slot, (duk_uint32_t) val);
18093#else
18094 if (val <= DUK_FASTINT_MAX) { /* val is unsigned so >= 0 */
18095 /* XXX: take advantage of val being unsigned, no need to mask */
18096 DUK_TVAL_SET_FASTINT(tv_slot, (duk_int64_t) val);
18097 } else {
18098 duk_double_t = (duk_double_t) val;
18099 DUK_TVAL_SET_NUMBER(tv_slot, d);
18100 }
18101#endif
18102#else /* DUK_USE_FASTINT */
18103 duk_hthread *thr;
18104 duk_tval *tv_slot;
18105 duk_double_t d;
18106
18107 DUK_ASSERT_CTX_VALID(ctx);
18108 thr = (duk_hthread *) ctx;
18109 DUK__CHECK_SPACE();
18110 d = (duk_double_t) val;
18111 tv_slot = thr->valstack_top++;
18112 DUK_TVAL_SET_NUMBER(tv_slot, d);
18113#endif /* DUK_USE_FASTINT */
18114}
18115
18116DUK_EXTERNAL void duk_push_nan(duk_context *ctx) {
18117 duk_hthread *thr;
18118 duk_tval *tv_slot;
18119 duk_double_union du;
18120
18121 DUK_ASSERT_CTX_VALID(ctx);
18122 thr = (duk_hthread *) ctx;
18123 DUK__CHECK_SPACE();
18124 DUK_DBLUNION_SET_NAN(&du);
18125 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
18126 tv_slot = thr->valstack_top++;
18127 DUK_TVAL_SET_NUMBER(tv_slot, du.d);
18128}
18129
18130DUK_EXTERNAL const char *duk_push_lstring(duk_context *ctx, const char *str, duk_size_t len) {
18131 duk_hthread *thr = (duk_hthread *) ctx;
18132 duk_hstring *h;
18133 duk_tval *tv_slot;
18134
18135 DUK_ASSERT_CTX_VALID(ctx);
18136
18137 /* check stack before interning (avoid hanging temp) */
18138 if (thr->valstack_top >= thr->valstack_end) {
11fdf7f2 18139 DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
7c673cae
FG
18140 }
18141
18142 /* NULL with zero length represents an empty string; NULL with higher
18143 * length is also now trated like an empty string although it is
18144 * a bit dubious. This is unlike duk_push_string() which pushes a
18145 * 'null' if the input string is a NULL.
18146 */
18147 if (!str) {
18148 len = 0;
18149 }
18150
18151 /* Check for maximum string length */
18152 if (len > DUK_HSTRING_MAX_BYTELEN) {
11fdf7f2 18153 DUK_ERROR_RANGE(thr, DUK_STR_STRING_TOO_LONG);
7c673cae
FG
18154 }
18155
11fdf7f2 18156 h = duk_heap_string_intern_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len);
7c673cae
FG
18157 DUK_ASSERT(h != NULL);
18158
18159 tv_slot = thr->valstack_top++;
18160 DUK_TVAL_SET_STRING(tv_slot, h);
18161 DUK_HSTRING_INCREF(thr, h); /* no side effects */
18162
18163 return (const char *) DUK_HSTRING_GET_DATA(h);
18164}
18165
18166DUK_EXTERNAL const char *duk_push_string(duk_context *ctx, const char *str) {
18167 DUK_ASSERT_CTX_VALID(ctx);
18168
18169 if (str) {
18170 return duk_push_lstring(ctx, str, DUK_STRLEN(str));
18171 } else {
18172 duk_push_null(ctx);
18173 return NULL;
18174 }
18175}
18176
18177#ifdef DUK_USE_FILE_IO
18178/* This is a bit clunky because it is ANSI C portable. Should perhaps
18179 * relocate to another file because this is potentially platform
18180 * dependent.
18181 */
18182DUK_EXTERNAL const char *duk_push_string_file_raw(duk_context *ctx, const char *path, duk_uint_t flags) {
18183 duk_hthread *thr = (duk_hthread *) ctx;
18184 duk_file *f = NULL;
18185 char *buf;
18186 long sz; /* ANSI C typing */
18187
18188 DUK_ASSERT_CTX_VALID(ctx);
18189
18190 if (!path) {
18191 goto fail;
18192 }
18193 f = DUK_FOPEN(path, "rb");
18194 if (!f) {
18195 goto fail;
18196 }
18197 if (DUK_FSEEK(f, 0, SEEK_END) < 0) {
18198 goto fail;
18199 }
18200 sz = DUK_FTELL(f);
18201 if (sz < 0) {
18202 goto fail;
18203 }
18204 if (DUK_FSEEK(f, 0, SEEK_SET) < 0) {
18205 goto fail;
18206 }
18207 buf = (char *) duk_push_fixed_buffer(ctx, (duk_size_t) sz);
18208 DUK_ASSERT(buf != NULL);
18209 if ((duk_size_t) DUK_FREAD(buf, 1, (size_t) sz, f) != (duk_size_t) sz) {
18210 goto fail;
18211 }
18212 (void) DUK_FCLOSE(f); /* ignore fclose() error */
18213 f = NULL;
18214 return duk_to_string(ctx, -1);
18215
18216 fail:
18217 if (f) {
18218 DUK_FCLOSE(f);
18219 }
18220
18221 if (flags != 0) {
18222 DUK_ASSERT(flags == DUK_STRING_PUSH_SAFE); /* only flag now */
18223 duk_push_undefined(ctx);
18224 } else {
18225 /* XXX: string not shared because it is conditional */
11fdf7f2 18226 DUK_ERROR_TYPE(thr, "read file error");
7c673cae
FG
18227 }
18228 return NULL;
18229}
18230#else
18231DUK_EXTERNAL const char *duk_push_string_file_raw(duk_context *ctx, const char *path, duk_uint_t flags) {
18232 duk_hthread *thr = (duk_hthread *) ctx;
18233 DUK_ASSERT_CTX_VALID(ctx);
18234 DUK_UNREF(path);
18235
18236 if (flags != 0) {
18237 DUK_ASSERT(flags == DUK_STRING_PUSH_SAFE); /* only flag now */
18238 duk_push_undefined(ctx);
18239 } else {
18240 /* XXX: string not shared because it is conditional */
11fdf7f2 18241 DUK_ERROR_UNSUPPORTED(thr, "file I/O disabled");
7c673cae
FG
18242 }
18243 return NULL;
18244}
18245#endif /* DUK_USE_FILE_IO */
18246
18247DUK_EXTERNAL void duk_push_pointer(duk_context *ctx, void *val) {
18248 duk_hthread *thr;
18249 duk_tval *tv_slot;
18250
18251 DUK_ASSERT_CTX_VALID(ctx);
18252 thr = (duk_hthread *) ctx;
18253 DUK__CHECK_SPACE();
18254 tv_slot = thr->valstack_top++;
18255 DUK_TVAL_SET_POINTER(tv_slot, val);
18256}
18257
11fdf7f2
TL
18258DUK_LOCAL void duk__push_this_helper(duk_context *ctx, duk_small_uint_t check_object_coercible) {
18259 duk_hthread *thr;
18260 duk_tval *tv_slot;
7c673cae 18261
7c673cae
FG
18262 DUK_ASSERT_CTX_VALID(ctx);
18263 DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */
11fdf7f2 18264 thr = (duk_hthread *) ctx;
7c673cae 18265 DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
11fdf7f2 18266 DUK__CHECK_SPACE();
7c673cae 18267
11fdf7f2
TL
18268 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* because of valstack init policy */
18269 tv_slot = thr->valstack_top++;
18270
18271 if (DUK_UNLIKELY(thr->callstack_top == 0)) {
18272 if (check_object_coercible) {
7c673cae
FG
18273 goto type_error;
18274 }
11fdf7f2 18275 /* 'undefined' already on stack top */
7c673cae 18276 } else {
7c673cae
FG
18277 duk_tval *tv;
18278
18279 /* 'this' binding is just before current activation's bottom */
18280 DUK_ASSERT(thr->valstack_bottom > thr->valstack);
18281 tv = thr->valstack_bottom - 1;
11fdf7f2
TL
18282 if (check_object_coercible &&
18283 (DUK_TVAL_IS_UNDEFINED(tv) || DUK_TVAL_IS_NULL(tv))) {
18284 /* XXX: better macro for DUK_TVAL_IS_UNDEFINED_OR_NULL(tv) */
18285 goto type_error;
7c673cae
FG
18286 }
18287
11fdf7f2
TL
18288 DUK_TVAL_SET_TVAL(tv_slot, tv);
18289 DUK_TVAL_INCREF(thr, tv);
7c673cae 18290 }
7c673cae
FG
18291 return;
18292
18293 type_error:
11fdf7f2 18294 DUK_ERROR_TYPE(thr, DUK_STR_NOT_OBJECT_COERCIBLE);
7c673cae
FG
18295}
18296
18297DUK_EXTERNAL void duk_push_this(duk_context *ctx) {
18298 DUK_ASSERT_CTX_VALID(ctx);
18299
11fdf7f2 18300 duk__push_this_helper(ctx, 0 /*check_object_coercible*/);
7c673cae
FG
18301}
18302
18303DUK_INTERNAL void duk_push_this_check_object_coercible(duk_context *ctx) {
18304 DUK_ASSERT_CTX_VALID(ctx);
18305
11fdf7f2 18306 duk__push_this_helper(ctx, 1 /*check_object_coercible*/);
7c673cae
FG
18307}
18308
18309DUK_INTERNAL duk_hobject *duk_push_this_coercible_to_object(duk_context *ctx) {
18310 duk_hobject *h;
18311
18312 DUK_ASSERT_CTX_VALID(ctx);
18313
11fdf7f2
TL
18314 duk__push_this_helper(ctx, 1 /*check_object_coercible*/);
18315 duk_to_object(ctx, -1);
7c673cae
FG
18316 h = duk_get_hobject(ctx, -1);
18317 DUK_ASSERT(h != NULL);
18318 return h;
18319}
18320
18321DUK_INTERNAL duk_hstring *duk_push_this_coercible_to_string(duk_context *ctx) {
18322 duk_hstring *h;
18323
18324 DUK_ASSERT_CTX_VALID(ctx);
18325
11fdf7f2
TL
18326 duk__push_this_helper(ctx, 1 /*check_object_coercible*/);
18327 duk_to_string(ctx, -1);
7c673cae
FG
18328 h = duk_get_hstring(ctx, -1);
18329 DUK_ASSERT(h != NULL);
18330 return h;
18331}
18332
18333DUK_INTERNAL duk_tval *duk_get_borrowed_this_tval(duk_context *ctx) {
18334 duk_hthread *thr;
18335
18336 DUK_ASSERT(ctx != NULL);
18337 thr = (duk_hthread *) ctx;
18338
18339 DUK_ASSERT(thr->callstack_top > 0); /* caller required to know */
18340 DUK_ASSERT(thr->valstack_bottom > thr->valstack); /* consequence of above */
18341 DUK_ASSERT(thr->valstack_bottom - 1 >= thr->valstack); /* 'this' binding exists */
18342
18343 return thr->valstack_bottom - 1;
18344}
18345
18346DUK_EXTERNAL void duk_push_current_function(duk_context *ctx) {
18347 duk_hthread *thr = (duk_hthread *) ctx;
18348 duk_activation *act;
18349
18350 DUK_ASSERT_CTX_VALID(ctx);
18351 DUK_ASSERT(thr != NULL);
18352 DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
18353 DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
18354
18355 act = duk_hthread_get_current_activation(thr);
18356 if (act) {
18357 duk_push_tval(ctx, &act->tv_func);
18358 } else {
18359 duk_push_undefined(ctx);
18360 }
18361}
18362
18363DUK_EXTERNAL void duk_push_current_thread(duk_context *ctx) {
18364 duk_hthread *thr = (duk_hthread *) ctx;
18365
18366 DUK_ASSERT_CTX_VALID(ctx);
18367 DUK_ASSERT(thr != NULL);
18368
18369 if (thr->heap->curr_thread) {
18370 duk_push_hobject(ctx, (duk_hobject *) thr->heap->curr_thread);
18371 } else {
18372 duk_push_undefined(ctx);
18373 }
18374}
18375
18376DUK_EXTERNAL void duk_push_global_object(duk_context *ctx) {
18377 DUK_ASSERT_CTX_VALID(ctx);
18378
18379 duk_push_hobject_bidx(ctx, DUK_BIDX_GLOBAL);
18380}
18381
18382/* XXX: size optimize */
18383DUK_LOCAL void duk__push_stash(duk_context *ctx) {
18384 DUK_ASSERT_CTX_VALID(ctx);
18385 if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE)) {
18386 DUK_DDD(DUK_DDDPRINT("creating heap/global/thread stash on first use"));
18387 duk_pop(ctx);
18388 duk_push_object_internal(ctx);
18389 duk_dup_top(ctx);
18390 duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_C); /* [ ... parent stash stash ] -> [ ... parent stash ] */
18391 }
18392 duk_remove(ctx, -2);
18393}
18394
18395DUK_EXTERNAL void duk_push_heap_stash(duk_context *ctx) {
18396 duk_hthread *thr = (duk_hthread *) ctx;
18397 duk_heap *heap;
18398 DUK_ASSERT_CTX_VALID(ctx);
18399 heap = thr->heap;
18400 DUK_ASSERT(heap->heap_object != NULL);
18401 duk_push_hobject(ctx, heap->heap_object);
18402 duk__push_stash(ctx);
18403}
18404
18405DUK_EXTERNAL void duk_push_global_stash(duk_context *ctx) {
18406 DUK_ASSERT_CTX_VALID(ctx);
18407 duk_push_global_object(ctx);
18408 duk__push_stash(ctx);
18409}
18410
18411DUK_EXTERNAL void duk_push_thread_stash(duk_context *ctx, duk_context *target_ctx) {
18412 duk_hthread *thr = (duk_hthread *) ctx;
18413 DUK_ASSERT_CTX_VALID(ctx);
18414 if (!target_ctx) {
11fdf7f2 18415 DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
7c673cae
FG
18416 return; /* not reached */
18417 }
18418 duk_push_hobject(ctx, (duk_hobject *) target_ctx);
18419 duk__push_stash(ctx);
18420}
18421
18422/* XXX: duk_ssize_t would be useful here */
18423DUK_LOCAL duk_int_t duk__try_push_vsprintf(duk_context *ctx, void *buf, duk_size_t sz, const char *fmt, va_list ap) {
18424 duk_int_t len;
18425
18426 DUK_ASSERT_CTX_VALID(ctx);
18427 DUK_UNREF(ctx);
18428
18429 /* NUL terminator handling doesn't matter here */
18430 len = DUK_VSNPRINTF((char *) buf, sz, fmt, ap);
18431 if (len < (duk_int_t) sz) {
18432 /* Return value of 'sz' or more indicates output was (potentially)
18433 * truncated.
18434 */
18435 return (duk_int_t) len;
18436 }
18437 return -1;
18438}
18439
18440DUK_EXTERNAL const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va_list ap) {
18441 duk_hthread *thr = (duk_hthread *) ctx;
18442 duk_uint8_t stack_buf[DUK_PUSH_SPRINTF_INITIAL_SIZE];
18443 duk_size_t sz = DUK_PUSH_SPRINTF_INITIAL_SIZE;
18444 duk_bool_t pushed_buf = 0;
18445 void *buf;
18446 duk_int_t len; /* XXX: duk_ssize_t */
18447 const char *res;
18448
18449 DUK_ASSERT_CTX_VALID(ctx);
18450
18451 /* special handling of fmt==NULL */
18452 if (!fmt) {
18453 duk_hstring *h_str;
18454 duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
18455 h_str = DUK_HTHREAD_STRING_EMPTY_STRING(thr); /* rely on interning, must be this string */
18456 return (const char *) DUK_HSTRING_GET_DATA(h_str);
18457 }
18458
18459 /* initial estimate based on format string */
18460 sz = DUK_STRLEN(fmt) + 16; /* format plus something to avoid just missing */
18461 if (sz < DUK_PUSH_SPRINTF_INITIAL_SIZE) {
18462 sz = DUK_PUSH_SPRINTF_INITIAL_SIZE;
18463 }
18464 DUK_ASSERT(sz > 0);
18465
18466 /* Try to make do with a stack buffer to avoid allocating a temporary buffer.
18467 * This works 99% of the time which is quite nice.
18468 */
18469 for (;;) {
18470 va_list ap_copy; /* copied so that 'ap' can be reused */
18471
18472 if (sz <= sizeof(stack_buf)) {
18473 buf = stack_buf;
18474 } else if (!pushed_buf) {
18475 pushed_buf = 1;
18476 buf = duk_push_dynamic_buffer(ctx, sz);
18477 } else {
18478 buf = duk_resize_buffer(ctx, -1, sz);
18479 }
18480 DUK_ASSERT(buf != NULL);
18481
18482 DUK_VA_COPY(ap_copy, ap);
18483 len = duk__try_push_vsprintf(ctx, buf, sz, fmt, ap_copy);
18484 va_end(ap_copy);
18485 if (len >= 0) {
18486 break;
18487 }
18488
18489 /* failed, resize and try again */
18490 sz = sz * 2;
18491 if (sz >= DUK_PUSH_SPRINTF_SANITY_LIMIT) {
11fdf7f2 18492 DUK_ERROR_API(thr, DUK_STR_SPRINTF_TOO_LONG);
7c673cae
FG
18493 }
18494 }
18495
18496 /* Cannot use duk_to_string() on the buffer because it is usually
18497 * larger than 'len'. Also, 'buf' is usually a stack buffer.
18498 */
18499 res = duk_push_lstring(ctx, (const char *) buf, (duk_size_t) len); /* [ buf? res ] */
18500 if (pushed_buf) {
18501 duk_remove(ctx, -2);
18502 }
18503 return res;
18504}
18505
18506DUK_EXTERNAL const char *duk_push_sprintf(duk_context *ctx, const char *fmt, ...) {
18507 va_list ap;
18508 const char *ret;
18509
18510 DUK_ASSERT_CTX_VALID(ctx);
18511
18512 /* allow fmt==NULL */
18513 va_start(ap, fmt);
18514 ret = duk_push_vsprintf(ctx, fmt, ap);
18515 va_end(ap);
18516
18517 return ret;
18518}
18519
18520DUK_INTERNAL duk_idx_t duk_push_object_helper(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) {
18521 duk_hthread *thr = (duk_hthread *) ctx;
18522 duk_tval *tv_slot;
18523 duk_hobject *h;
18524 duk_idx_t ret;
18525
18526 DUK_ASSERT_CTX_VALID(ctx);
18527 DUK_ASSERT(prototype_bidx == -1 ||
18528 (prototype_bidx >= 0 && prototype_bidx < DUK_NUM_BUILTINS));
18529
18530 /* check stack first */
18531 if (thr->valstack_top >= thr->valstack_end) {
11fdf7f2 18532 DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
7c673cae
FG
18533 }
18534
18535 h = duk_hobject_alloc(thr->heap, hobject_flags_and_class);
18536 if (!h) {
11fdf7f2 18537 DUK_ERROR_ALLOC_DEFMSG(thr);
7c673cae
FG
18538 }
18539
18540 DUK_DDD(DUK_DDDPRINT("created object with flags: 0x%08lx", (unsigned long) h->hdr.h_flags));
18541
18542 tv_slot = thr->valstack_top;
18543 DUK_TVAL_SET_OBJECT(tv_slot, h);
18544 DUK_HOBJECT_INCREF(thr, h); /* no side effects */
18545 ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
18546 thr->valstack_top++;
18547
18548 /* object is now reachable */
18549
18550 if (prototype_bidx >= 0) {
18551 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[prototype_bidx]);
18552 } else {
18553 DUK_ASSERT(prototype_bidx == -1);
18554 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h) == NULL);
18555 }
18556
18557 return ret;
18558}
18559
18560DUK_INTERNAL duk_idx_t duk_push_object_helper_proto(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_hobject *proto) {
18561 duk_hthread *thr = (duk_hthread *) ctx;
18562 duk_idx_t ret;
18563 duk_hobject *h;
18564
18565 DUK_ASSERT_CTX_VALID(ctx);
18566
18567 ret = duk_push_object_helper(ctx, hobject_flags_and_class, -1);
18568 h = duk_get_hobject(ctx, -1);
18569 DUK_ASSERT(h != NULL);
18570 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h) == NULL);
18571 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, proto);
18572 return ret;
18573}
18574
18575DUK_EXTERNAL duk_idx_t duk_push_object(duk_context *ctx) {
18576 DUK_ASSERT_CTX_VALID(ctx);
18577
18578 return duk_push_object_helper(ctx,
18579 DUK_HOBJECT_FLAG_EXTENSIBLE |
18580 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
18581 DUK_BIDX_OBJECT_PROTOTYPE);
18582}
18583
18584DUK_EXTERNAL duk_idx_t duk_push_array(duk_context *ctx) {
18585 duk_hthread *thr = (duk_hthread *) ctx;
18586 duk_hobject *obj;
18587 duk_idx_t ret;
18588
18589 DUK_ASSERT_CTX_VALID(ctx);
18590
18591 ret = duk_push_object_helper(ctx,
18592 DUK_HOBJECT_FLAG_EXTENSIBLE |
18593 DUK_HOBJECT_FLAG_ARRAY_PART |
18594 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAY),
18595 DUK_BIDX_ARRAY_PROTOTYPE);
18596
18597 obj = duk_require_hobject(ctx, ret);
18598
18599 /*
18600 * An array must have a 'length' property (E5 Section 15.4.5.2).
18601 * The special array behavior flag must only be enabled once the
18602 * length property has been added.
18603 *
18604 * The internal property must be a number (and preferably a
18605 * fastint if fastint support is enabled).
18606 */
18607
18608 duk_push_int(ctx, 0);
18609#if defined(DUK_USE_FASTINT)
18610 DUK_ASSERT(DUK_TVAL_IS_FASTINT(duk_require_tval(ctx, -1)));
18611#endif
18612
18613 duk_hobject_define_property_internal(thr,
18614 obj,
18615 DUK_HTHREAD_STRING_LENGTH(thr),
18616 DUK_PROPDESC_FLAGS_W);
18617 DUK_HOBJECT_SET_EXOTIC_ARRAY(obj);
18618
18619 return ret;
18620}
18621
18622DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags) {
18623 duk_hthread *thr = (duk_hthread *) ctx;
18624 duk_hthread *obj;
18625 duk_idx_t ret;
18626 duk_tval *tv_slot;
18627
18628 DUK_ASSERT_CTX_VALID(ctx);
18629
18630 /* check stack first */
18631 if (thr->valstack_top >= thr->valstack_end) {
11fdf7f2 18632 DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
7c673cae
FG
18633 }
18634
18635 obj = duk_hthread_alloc(thr->heap,
18636 DUK_HOBJECT_FLAG_EXTENSIBLE |
18637 DUK_HOBJECT_FLAG_THREAD |
18638 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD));
18639 if (!obj) {
11fdf7f2 18640 DUK_ERROR_ALLOC_DEFMSG(thr);
7c673cae
FG
18641 }
18642 obj->state = DUK_HTHREAD_STATE_INACTIVE;
11fdf7f2
TL
18643#if defined(DUK_USE_ROM_STRINGS)
18644 /* Nothing to initialize, strs[] is in ROM. */
18645#else
7c673cae
FG
18646#if defined(DUK_USE_HEAPPTR16)
18647 obj->strs16 = thr->strs16;
18648#else
18649 obj->strs = thr->strs;
11fdf7f2 18650#endif
7c673cae
FG
18651#endif
18652 DUK_DDD(DUK_DDDPRINT("created thread object with flags: 0x%08lx", (unsigned long) obj->obj.hdr.h_flags));
18653
18654 /* make the new thread reachable */
18655 tv_slot = thr->valstack_top;
18656 DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
18657 DUK_HTHREAD_INCREF(thr, obj);
18658 ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
18659 thr->valstack_top++;
18660
18661 /* important to do this *after* pushing, to make the thread reachable for gc */
18662 if (!duk_hthread_init_stacks(thr->heap, obj)) {
11fdf7f2 18663 DUK_ERROR_ALLOC_DEFMSG(thr);
7c673cae
FG
18664 }
18665
18666 /* initialize built-ins - either by copying or creating new ones */
18667 if (flags & DUK_THREAD_NEW_GLOBAL_ENV) {
18668 duk_hthread_create_builtin_objects(obj);
18669 } else {
18670 duk_hthread_copy_builtin_objects(thr, obj);
18671 }
18672
18673 /* default prototype (Note: 'obj' must be reachable) */
18674 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, obj->builtins[DUK_BIDX_THREAD_PROTOTYPE]);
18675
18676 /* Initial stack size satisfies the stack spare constraints so there
18677 * is no need to require stack here.
18678 */
18679 DUK_ASSERT(DUK_VALSTACK_INITIAL_SIZE >=
18680 DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA);
18681
18682 return ret;
18683}
18684
18685DUK_INTERNAL duk_idx_t duk_push_compiledfunction(duk_context *ctx) {
18686 duk_hthread *thr = (duk_hthread *) ctx;
18687 duk_hcompiledfunction *obj;
18688 duk_idx_t ret;
18689 duk_tval *tv_slot;
18690
18691 DUK_ASSERT_CTX_VALID(ctx);
18692
18693 /* check stack first */
18694 if (thr->valstack_top >= thr->valstack_end) {
11fdf7f2 18695 DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
7c673cae
FG
18696 }
18697
18698 /* Template functions are not strictly constructable (they don't
18699 * have a "prototype" property for instance), so leave the
18700 * DUK_HOBJECT_FLAG_CONSRUCTABLE flag cleared here.
18701 */
18702
18703 obj = duk_hcompiledfunction_alloc(thr->heap,
18704 DUK_HOBJECT_FLAG_EXTENSIBLE |
18705 DUK_HOBJECT_FLAG_COMPILEDFUNCTION |
18706 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION));
18707 if (!obj) {
11fdf7f2 18708 DUK_ERROR_ALLOC_DEFMSG(thr);
7c673cae
FG
18709 }
18710
18711 DUK_DDD(DUK_DDDPRINT("created compiled function object with flags: 0x%08lx", (unsigned long) obj->obj.hdr.h_flags));
18712
18713 tv_slot = thr->valstack_top;
18714 DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
18715 DUK_HOBJECT_INCREF(thr, obj);
18716 ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
18717 thr->valstack_top++;
18718
18719 /* default prototype (Note: 'obj' must be reachable) */
18720 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
18721
18722 return ret;
18723}
18724
18725DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function func, duk_idx_t nargs, duk_uint_t flags) {
18726 duk_hthread *thr = (duk_hthread *) ctx;
18727 duk_hnativefunction *obj;
18728 duk_idx_t ret;
18729 duk_tval *tv_slot;
11fdf7f2 18730 duk_int16_t func_nargs;
7c673cae
FG
18731
18732 DUK_ASSERT_CTX_VALID(ctx);
18733
18734 /* check stack first */
18735 if (thr->valstack_top >= thr->valstack_end) {
11fdf7f2 18736 DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
7c673cae
FG
18737 }
18738 if (func == NULL) {
18739 goto api_error;
18740 }
18741 if (nargs >= 0 && nargs < DUK_HNATIVEFUNCTION_NARGS_MAX) {
11fdf7f2 18742 func_nargs = (duk_int16_t) nargs;
7c673cae
FG
18743 } else if (nargs == DUK_VARARGS) {
18744 func_nargs = DUK_HNATIVEFUNCTION_NARGS_VARARGS;
18745 } else {
18746 goto api_error;
18747 }
18748
18749 obj = duk_hnativefunction_alloc(thr->heap, flags);
18750 if (!obj) {
11fdf7f2 18751 DUK_ERROR_ALLOC_DEFMSG(thr);
7c673cae
FG
18752 }
18753
18754 obj->func = func;
18755 obj->nargs = func_nargs;
18756
18757 DUK_DDD(DUK_DDDPRINT("created native function object with flags: 0x%08lx, nargs=%ld",
18758 (unsigned long) obj->obj.hdr.h_flags, (long) obj->nargs));
18759
18760 tv_slot = thr->valstack_top;
18761 DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
18762 DUK_HOBJECT_INCREF(thr, obj);
18763 ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
18764 thr->valstack_top++;
18765
18766 /* default prototype (Note: 'obj' must be reachable) */
18767 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
18768
18769 return ret;
18770
18771 api_error:
11fdf7f2 18772 DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
7c673cae
FG
18773 return 0; /* not reached */
18774}
18775
18776DUK_EXTERNAL duk_idx_t duk_push_c_function(duk_context *ctx, duk_c_function func, duk_int_t nargs) {
18777 duk_uint_t flags;
18778
18779 DUK_ASSERT_CTX_VALID(ctx);
18780
18781 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
18782 DUK_HOBJECT_FLAG_CONSTRUCTABLE |
18783 DUK_HOBJECT_FLAG_NATIVEFUNCTION |
18784 DUK_HOBJECT_FLAG_NEWENV |
18785 DUK_HOBJECT_FLAG_STRICT |
18786 DUK_HOBJECT_FLAG_NOTAIL |
18787 DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC |
18788 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
18789
18790 return duk__push_c_function_raw(ctx, func, nargs, flags);
18791}
18792
18793DUK_INTERNAL void duk_push_c_function_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs) {
18794 duk_uint_t flags;
18795
18796 DUK_ASSERT_CTX_VALID(ctx);
18797
18798 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
18799 DUK_HOBJECT_FLAG_CONSTRUCTABLE |
18800 DUK_HOBJECT_FLAG_NATIVEFUNCTION |
18801 DUK_HOBJECT_FLAG_NEWENV |
18802 DUK_HOBJECT_FLAG_STRICT |
18803 DUK_HOBJECT_FLAG_NOTAIL |
18804 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
18805
18806 (void) duk__push_c_function_raw(ctx, func, nargs, flags);
18807}
18808
18809DUK_INTERNAL void duk_push_c_function_noconstruct_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs) {
18810 duk_uint_t flags;
18811
18812 DUK_ASSERT_CTX_VALID(ctx);
18813
18814 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
18815 DUK_HOBJECT_FLAG_NATIVEFUNCTION |
18816 DUK_HOBJECT_FLAG_NEWENV |
18817 DUK_HOBJECT_FLAG_STRICT |
18818 DUK_HOBJECT_FLAG_NOTAIL |
18819 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
18820
18821 (void) duk__push_c_function_raw(ctx, func, nargs, flags);
18822}
18823
18824DUK_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) {
18825 duk_hthread *thr = (duk_hthread *) ctx;
18826 duk_tval tv_tmp;
18827 duk_small_uint_t lf_flags;
18828
18829 DUK_ASSERT_CTX_VALID(ctx);
18830
18831 /* check stack first */
18832 if (thr->valstack_top >= thr->valstack_end) {
11fdf7f2 18833 DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
7c673cae
FG
18834 }
18835
18836 if (nargs >= DUK_LFUNC_NARGS_MIN && nargs <= DUK_LFUNC_NARGS_MAX) {
18837 /* as is */
18838 } else if (nargs == DUK_VARARGS) {
18839 nargs = DUK_LFUNC_NARGS_VARARGS;
18840 } else {
18841 goto api_error;
18842 }
18843 if (!(length >= DUK_LFUNC_LENGTH_MIN && length <= DUK_LFUNC_LENGTH_MAX)) {
18844 goto api_error;
18845 }
18846 if (!(magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX)) {
18847 goto api_error;
18848 }
18849
18850 lf_flags = DUK_LFUNC_FLAGS_PACK(magic, length, nargs);
18851 DUK_TVAL_SET_LIGHTFUNC(&tv_tmp, func, lf_flags);
18852 duk_push_tval(ctx, &tv_tmp); /* XXX: direct valstack write */
18853 DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
18854 return ((duk_idx_t) (thr->valstack_top - thr->valstack_bottom)) - 1;
18855
18856 api_error:
11fdf7f2 18857 DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
7c673cae
FG
18858 return 0; /* not reached */
18859}
18860
18861DUK_INTERNAL duk_hbufferobject *duk_push_bufferobject_raw(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) {
18862 duk_hthread *thr = (duk_hthread *) ctx;
18863 duk_hbufferobject *obj;
18864 duk_tval *tv_slot;
18865
18866 DUK_ASSERT(ctx != NULL);
18867 DUK_ASSERT(prototype_bidx >= 0);
18868
18869 /* check stack first */
18870 if (thr->valstack_top >= thr->valstack_end) {
11fdf7f2 18871 DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
7c673cae
FG
18872 }
18873
18874 obj = duk_hbufferobject_alloc(thr->heap, hobject_flags_and_class);
18875 if (!obj) {
11fdf7f2 18876 DUK_ERROR_ALLOC_DEFMSG(thr);
7c673cae
FG
18877 }
18878
18879 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[prototype_bidx]);
18880 DUK_ASSERT_HBUFFEROBJECT_VALID(obj);
18881
18882 tv_slot = thr->valstack_top;
18883 DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
18884 DUK_HOBJECT_INCREF(thr, obj);
18885 thr->valstack_top++;
18886
18887 return obj;
18888}
18889
18890/* XXX: There's quite a bit of overlap with buffer creation handling in
18891 * duk_bi_buffer.c. Look for overlap and refactor.
18892 */
18893#define DUK__PACK_ARGS(classnum,protobidx,elemtype,elemshift,isview) \
18894 (((classnum) << 24) | ((protobidx) << 16) | ((elemtype) << 8) | ((elemshift) << 4) | (isview))
18895
18896#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
18897static const duk_uint32_t duk__bufobj_flags_lookup[] = {
18898 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_BUFFER, DUK_BIDX_BUFFER_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_DUKTAPE_BUFFER */
18899 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_BUFFER, DUK_BIDX_NODEJS_BUFFER_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_NODEJS_BUFFER */
18900 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_ARRAYBUFFER, DUK_BIDX_ARRAYBUFFER_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_ARRAYBUFFER */
18901 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_DATAVIEW, DUK_BIDX_DATAVIEW_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 1), /* DUK_BUFOBJ_DATAVIEW */
18902 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT8ARRAY, DUK_BIDX_INT8ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_INT8, 0, 1), /* DUK_BUFOBJ_INT8ARRAY */
18903 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8ARRAY, DUK_BIDX_UINT8ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 1), /* DUK_BUFOBJ_UINT8ARRAY */
18904 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY, DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED, 0, 1), /* DUK_BUFOBJ_UINT8CLAMPEDARRAY */
18905 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT16ARRAY, DUK_BIDX_INT16ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_INT16, 1, 1), /* DUK_BUFOBJ_INT16ARRAY */
18906 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT16ARRAY, DUK_BIDX_UINT16ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT16, 1, 1), /* DUK_BUFOBJ_UINT16ARRAY */
18907 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT32ARRAY, DUK_BIDX_INT32ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_INT32, 2, 1), /* DUK_BUFOBJ_INT32ARRAY */
18908 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT32ARRAY, DUK_BIDX_UINT32ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT32, 2, 1), /* DUK_BUFOBJ_UINT32ARRAY */
18909 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT32ARRAY, DUK_BIDX_FLOAT32ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_FLOAT32, 2, 1), /* DUK_BUFOBJ_FLOAT32ARRAY */
18910 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT64ARRAY, DUK_BIDX_FLOAT64ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_FLOAT64, 3, 1) /* DUK_BUFOBJ_FLOAT64ARRAY */
18911};
18912#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
18913/* Only allow Duktape.Buffer when support disabled. */
18914static const duk_uint32_t duk__bufobj_flags_lookup[] = {
18915 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_BUFFER, DUK_BIDX_BUFFER_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 0) /* DUK_BUFOBJ_DUKTAPE_BUFFER */
18916};
18917#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
18918#undef DUK__PACK_ARGS
18919
18920DUK_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) {
18921 duk_hthread *thr;
18922 duk_hbufferobject *h_bufobj;
18923 duk_hbuffer *h_val;
18924 duk_uint32_t tmp;
18925 duk_uint_t classnum;
18926 duk_uint_t protobidx;
18927 duk_uint_t lookupidx;
18928 duk_uint_t uint_offset, uint_length, uint_added;
18929
18930 DUK_ASSERT_CTX_VALID(ctx);
18931 thr = (duk_hthread *) ctx;
18932 DUK_UNREF(thr);
18933
18934 /* The underlying types for offset/length in duk_hbufferobject is
18935 * duk_uint_t; make sure argument values fit and that offset + length
18936 * does not wrap.
18937 */
18938 uint_offset = (duk_uint_t) byte_offset;
18939 uint_length = (duk_uint_t) byte_length;
18940 if (sizeof(duk_size_t) != sizeof(duk_uint_t)) {
18941 if ((duk_size_t) uint_offset != byte_offset || (duk_size_t) uint_length != byte_length) {
18942 goto range_error;
18943 }
18944 }
18945 uint_added = uint_offset + uint_length;
18946 if (uint_added < uint_offset) {
18947 goto range_error;
18948 }
18949 DUK_ASSERT(uint_added >= uint_offset && uint_added >= uint_length);
18950
18951 DUK_ASSERT_DISABLE(flags >= 0); /* flags is unsigned */
18952 lookupidx = flags & 0x0f; /* 4 low bits */
18953 if (lookupidx >= sizeof(duk__bufobj_flags_lookup) / sizeof(duk_uint32_t)) {
18954 goto arg_error;
18955 }
18956 tmp = duk__bufobj_flags_lookup[lookupidx];
18957 classnum = tmp >> 24;
18958 protobidx = (tmp >> 16) & 0xff;
18959
18960 h_val = duk_require_hbuffer(ctx, idx_buffer);
18961 DUK_ASSERT(h_val != NULL);
18962
18963 h_bufobj = duk_push_bufferobject_raw(ctx,
18964 DUK_HOBJECT_FLAG_EXTENSIBLE |
18965 DUK_HOBJECT_FLAG_BUFFEROBJECT |
18966 DUK_HOBJECT_CLASS_AS_FLAGS(classnum),
18967 protobidx);
18968 DUK_ASSERT(h_bufobj != NULL);
18969
18970 h_bufobj->buf = h_val;
18971 DUK_HBUFFER_INCREF(thr, h_val);
18972 h_bufobj->offset = uint_offset;
18973 h_bufobj->length = uint_length;
18974 h_bufobj->shift = (tmp >> 4) & 0x0f;
18975 h_bufobj->elem_type = (tmp >> 8) & 0xff;
18976 h_bufobj->is_view = tmp & 0x0f;
18977 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
18978
18979#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
18980 /* TypedArray views need an automatic ArrayBuffer which must be
18981 * provided as .buffer property of the view. Just create a new
18982 * ArrayBuffer sharing the same underlying buffer.
11fdf7f2
TL
18983 *
18984 * The ArrayBuffer offset is always set to zero, so that if one
18985 * accesses the ArrayBuffer at the view's .byteOffset, the value
18986 * matches the view at index 0.
7c673cae
FG
18987 */
18988 if (flags & DUK_BUFOBJ_CREATE_ARRBUF) {
18989 h_bufobj = duk_push_bufferobject_raw(ctx,
18990 DUK_HOBJECT_FLAG_EXTENSIBLE |
18991 DUK_HOBJECT_FLAG_BUFFEROBJECT |
18992 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
18993 DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
18994
18995 DUK_ASSERT(h_bufobj != NULL);
18996
18997 h_bufobj->buf = h_val;
18998 DUK_HBUFFER_INCREF(thr, h_val);
11fdf7f2
TL
18999 h_bufobj->offset = 0;
19000 h_bufobj->length = uint_offset + uint_length; /* Wrap checked above. */
7c673cae
FG
19001 DUK_ASSERT(h_bufobj->shift == 0);
19002 h_bufobj->elem_type = DUK_HBUFFEROBJECT_ELEM_UINT8;
19003 DUK_ASSERT(h_bufobj->is_view == 0);
19004 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
19005
19006 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE);
19007 duk_compact(ctx, -1);
19008 }
19009#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
19010
19011 return;
19012
19013 range_error:
11fdf7f2 19014 DUK_ERROR_RANGE(thr, DUK_STR_INVALID_CALL_ARGS);
7c673cae
FG
19015 return; /* not reached */
19016
19017 arg_error:
11fdf7f2 19018 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_CALL_ARGS);
7c673cae
FG
19019 return; /* not reached */
19020}
19021
19022DUK_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) {
19023 duk_hthread *thr = (duk_hthread *) ctx;
19024 duk_idx_t ret;
19025 duk_hobject *proto;
19026#ifdef DUK_USE_AUGMENT_ERROR_CREATE
19027 duk_bool_t noblame_fileline;
19028#endif
19029
19030 DUK_ASSERT_CTX_VALID(ctx);
19031 DUK_ASSERT(thr != NULL);
19032 DUK_UNREF(filename);
19033 DUK_UNREF(line);
19034
19035 /* Error code also packs a tracedata related flag. */
19036#ifdef DUK_USE_AUGMENT_ERROR_CREATE
19037 noblame_fileline = err_code & DUK_ERRCODE_FLAG_NOBLAME_FILELINE;
19038#endif
19039 err_code = err_code & (~DUK_ERRCODE_FLAG_NOBLAME_FILELINE);
19040
19041 /* error gets its 'name' from the prototype */
19042 proto = duk_error_prototype_from_code(thr, err_code);
19043 ret = duk_push_object_helper_proto(ctx,
19044 DUK_HOBJECT_FLAG_EXTENSIBLE |
19045 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR),
19046 proto);
19047
19048 /* ... and its 'message' from an instance property */
19049 if (fmt) {
19050 duk_push_vsprintf(ctx, fmt, ap);
19051 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
19052 } else {
19053 /* If no explicit message given, put error code into message field
19054 * (as a number). This is not fully in keeping with the Ecmascript
19055 * error model because messages are supposed to be strings (Error
19056 * constructors use ToString() on their argument). However, it's
19057 * probably more useful than having a separate 'code' property.
19058 */
19059 duk_push_int(ctx, err_code);
19060 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
19061 }
19062
11fdf7f2 19063 /* XXX: .code = err_code disabled, not sure if useful */
7c673cae
FG
19064
19065 /* Creation time error augmentation */
19066#ifdef DUK_USE_AUGMENT_ERROR_CREATE
19067 /* filename may be NULL in which case file/line is not recorded */
19068 duk_err_augment_error_create(thr, thr, filename, line, noblame_fileline); /* may throw an error */
19069#endif
19070
19071 return ret;
19072}
19073
19074DUK_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, ...) {
19075 va_list ap;
19076 duk_idx_t ret;
19077
19078 DUK_ASSERT_CTX_VALID(ctx);
19079
19080 va_start(ap, fmt);
19081 ret = duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
19082 va_end(ap);
19083 return ret;
19084}
19085
19086#if !defined(DUK_USE_VARIADIC_MACROS)
19087DUK_EXTERNAL duk_idx_t duk_push_error_object_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...) {
19088 const char *filename = duk_api_global_filename;
19089 duk_int_t line = duk_api_global_line;
19090 va_list ap;
19091 duk_idx_t ret;
19092
19093 DUK_ASSERT_CTX_VALID(ctx);
19094
19095 duk_api_global_filename = NULL;
19096 duk_api_global_line = 0;
19097 va_start(ap, fmt);
19098 ret = duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
19099 va_end(ap);
19100 return ret;
19101}
19102#endif /* DUK_USE_VARIADIC_MACROS */
19103
19104DUK_EXTERNAL void *duk_push_buffer_raw(duk_context *ctx, duk_size_t size, duk_small_uint_t flags) {
19105 duk_hthread *thr = (duk_hthread *) ctx;
19106 duk_tval *tv_slot;
19107 duk_hbuffer *h;
19108 void *buf_data;
19109
19110 DUK_ASSERT_CTX_VALID(ctx);
19111
19112 /* check stack first */
19113 if (thr->valstack_top >= thr->valstack_end) {
11fdf7f2 19114 DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
7c673cae
FG
19115 }
19116
19117 /* Check for maximum buffer length. */
19118 if (size > DUK_HBUFFER_MAX_BYTELEN) {
11fdf7f2 19119 DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG);
7c673cae
FG
19120 }
19121
19122 h = duk_hbuffer_alloc(thr->heap, size, flags, &buf_data);
19123 if (!h) {
11fdf7f2 19124 DUK_ERROR_ALLOC_DEFMSG(thr);
7c673cae
FG
19125 }
19126
19127 tv_slot = thr->valstack_top;
19128 DUK_TVAL_SET_BUFFER(tv_slot, h);
19129 DUK_HBUFFER_INCREF(thr, h);
19130 thr->valstack_top++;
19131
19132 return (void *) buf_data;
19133}
19134
11fdf7f2
TL
19135#if defined(DUK_USE_ASSERTIONS)
19136DUK_LOCAL void duk__validate_push_heapptr(duk_context *ctx, void *ptr) {
19137 duk_heaphdr *h;
19138 duk_heaphdr *curr;
19139 duk_hthread *thr;
19140 duk_bool_t found = 0;
19141
19142 thr = (duk_hthread *) ctx;
19143 h = (duk_heaphdr *) ptr;
19144 if (h == NULL) {
19145 /* Allowed. */
19146 return;
19147 }
19148 DUK_ASSERT(h != NULL);
19149 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
19150
19151 /* One particular problem case is where an object has been
19152 * queued for finalization but the finalizer hasn't yet been
19153 * executed.
19154 *
19155 * Corner case: we're running in a finalizer for object X, and
19156 * user code calls duk_push_heapptr() for X itself. In this
19157 * case X will be in finalize_list, and we can detect the case
19158 * by seeing that X's FINALIZED flag is set (which is done before
19159 * the finalizer starts executing).
19160 */
19161 for (curr = thr->heap->finalize_list;
19162 curr != NULL;
19163 curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) {
19164 if (curr == h) {
19165 if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h)) {
19166 /* Object is currently being finalized. */
19167 DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */
19168 found = 1;
19169 } else {
19170 DUK_ASSERT(0);
19171 }
19172 }
19173 }
19174
19175 /* Also check for the refzero_list; must not be there unless it is
19176 * being finalized when duk_push_heapptr() is called.
19177 *
19178 * Corner case: similar to finalize_list.
19179 */
19180#if defined(DUK_USE_REFERENCE_COUNTING)
19181 for (curr = thr->heap->refzero_list;
19182 curr != NULL;
19183 curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) {
19184 if (curr == h) {
19185 if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h)) {
19186 /* Object is currently being finalized. */
19187 DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */
19188 found = 1;
19189 } else {
19190 DUK_ASSERT(0);
19191 }
19192 }
19193 }
19194#endif
19195
19196 /* If not present in finalize_list or refzero_list, the pointer
19197 * must be either in heap_allocated or the string table.
19198 */
19199 if (DUK_HEAPHDR_GET_TYPE(h) == DUK_HTYPE_STRING) {
19200 /* String table assert check omitted from 1.x branch
19201 * backport.
19202 */
19203 } else {
19204 for (curr = thr->heap->heap_allocated;
19205 curr != NULL;
19206 curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) {
19207 if (curr == h) {
19208 DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */
19209 found = 1;
19210 }
19211 }
19212 DUK_ASSERT(found != 0);
19213 }
19214}
19215#endif /* DUK_USE_ASSERTIONS */
19216
7c673cae
FG
19217DUK_EXTERNAL duk_idx_t duk_push_heapptr(duk_context *ctx, void *ptr) {
19218 duk_hthread *thr = (duk_hthread *) ctx;
19219 duk_idx_t ret;
19220
19221 DUK_ASSERT_CTX_VALID(ctx);
19222
11fdf7f2
TL
19223 /* Reviving an object using a heap pointer is a dangerous API
19224 * operation: if the application doesn't guarantee that the
19225 * pointer target is always reachable, difficult-to-diagnose
19226 * problems may ensue. Try to validate the 'ptr' argument to
19227 * the extent possible.
19228 */
19229
19230#if defined(DUK_USE_ASSERTIONS)
19231 duk__validate_push_heapptr(ctx, ptr);
19232#endif
19233
7c673cae
FG
19234 ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
19235
19236 if (ptr == NULL) {
19237 goto push_undefined;
19238 }
19239
11fdf7f2 19240 switch ((int) DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr)) {
7c673cae
FG
19241 case DUK_HTYPE_STRING:
19242 duk_push_hstring(ctx, (duk_hstring *) ptr);
19243 break;
19244 case DUK_HTYPE_OBJECT:
19245 duk_push_hobject(ctx, (duk_hobject *) ptr);
19246 break;
19247 case DUK_HTYPE_BUFFER:
19248 duk_push_hbuffer(ctx, (duk_hbuffer *) ptr);
19249 break;
19250 default:
19251 goto push_undefined;
19252 }
19253 return ret;
19254
19255 push_undefined:
19256 duk_push_undefined(ctx);
19257 return ret;
19258}
19259
19260DUK_INTERNAL duk_idx_t duk_push_object_internal(duk_context *ctx) {
19261 return duk_push_object_helper(ctx,
19262 DUK_HOBJECT_FLAG_EXTENSIBLE |
19263 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
19264 -1); /* no prototype */
19265}
19266
19267DUK_INTERNAL void duk_push_hstring(duk_context *ctx, duk_hstring *h) {
19268 duk_tval tv;
19269 DUK_ASSERT_CTX_VALID(ctx);
19270 DUK_ASSERT(h != NULL);
19271 DUK_TVAL_SET_STRING(&tv, h);
19272 duk_push_tval(ctx, &tv);
19273}
19274
19275DUK_INTERNAL void duk_push_hstring_stridx(duk_context *ctx, duk_small_int_t stridx) {
19276 duk_hthread *thr = (duk_hthread *) ctx;
11fdf7f2 19277 DUK_UNREF(thr);
7c673cae
FG
19278 DUK_ASSERT(stridx >= 0 && stridx < DUK_HEAP_NUM_STRINGS);
19279 duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
19280}
19281
19282DUK_INTERNAL void duk_push_hobject(duk_context *ctx, duk_hobject *h) {
19283 duk_tval tv;
19284 DUK_ASSERT_CTX_VALID(ctx);
19285 DUK_ASSERT(h != NULL);
19286 DUK_TVAL_SET_OBJECT(&tv, h);
19287 duk_push_tval(ctx, &tv);
19288}
19289
19290DUK_INTERNAL void duk_push_hbuffer(duk_context *ctx, duk_hbuffer *h) {
19291 duk_tval tv;
19292 DUK_ASSERT_CTX_VALID(ctx);
19293 DUK_ASSERT(h != NULL);
19294 DUK_TVAL_SET_BUFFER(&tv, h);
19295 duk_push_tval(ctx, &tv);
19296}
19297
19298DUK_INTERNAL void duk_push_hobject_bidx(duk_context *ctx, duk_small_int_t builtin_idx) {
19299 duk_hthread *thr = (duk_hthread *) ctx;
19300 DUK_ASSERT_CTX_VALID(ctx);
19301 DUK_ASSERT(thr != NULL);
19302 DUK_ASSERT(builtin_idx >= 0 && builtin_idx < DUK_NUM_BUILTINS);
19303 DUK_ASSERT(thr->builtins[builtin_idx] != NULL);
19304 duk_push_hobject(ctx, thr->builtins[builtin_idx]);
19305}
19306
19307/*
19308 * Poppers
19309 */
19310
19311DUK_EXTERNAL void duk_pop_n(duk_context *ctx, duk_idx_t count) {
19312 duk_hthread *thr = (duk_hthread *) ctx;
11fdf7f2 19313 duk_tval *tv;
7c673cae
FG
19314
19315 DUK_ASSERT_CTX_VALID(ctx);
19316
11fdf7f2
TL
19317 if (DUK_UNLIKELY(count < 0)) {
19318 DUK_ERROR_API(thr, DUK_STR_INVALID_COUNT);
7c673cae
FG
19319 return;
19320 }
19321
19322 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
11fdf7f2
TL
19323 if (DUK_UNLIKELY((duk_size_t) (thr->valstack_top - thr->valstack_bottom) < (duk_size_t) count)) {
19324 DUK_ERROR_API(thr, DUK_STR_POP_TOO_MANY);
7c673cae
FG
19325 }
19326
19327 /*
19328 * Must be very careful here, every DECREF may cause reallocation
19329 * of our valstack.
19330 */
19331
19332 /* XXX: inlined DECREF macro would be nice here: no NULL check,
19333 * refzero queueing but no refzero algorithm run (= no pointer
19334 * instability), inline code.
19335 */
19336
11fdf7f2 19337 /* XXX: optimize loops */
7c673cae 19338
11fdf7f2
TL
19339#if defined(DUK_USE_REFERENCE_COUNTING)
19340 while (count > 0) {
19341 count--;
7c673cae
FG
19342 tv = --thr->valstack_top; /* tv points to element just below prev top */
19343 DUK_ASSERT(tv >= thr->valstack_bottom);
11fdf7f2 19344 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
7c673cae
FG
19345 }
19346#else
11fdf7f2 19347 tv = thr->valstack_top;
7c673cae 19348 while (count > 0) {
7c673cae 19349 count--;
11fdf7f2
TL
19350 tv--;
19351 DUK_ASSERT(tv >= thr->valstack_bottom);
19352 DUK_TVAL_SET_UNDEFINED(tv);
7c673cae 19353 }
11fdf7f2 19354 thr->valstack_top = tv;
7c673cae
FG
19355#endif
19356
19357 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
19358}
19359
11fdf7f2
TL
19360/* Popping one element is called so often that when footprint is not an issue,
19361 * compile a specialized function for it.
19362 */
19363#if defined(DUK_USE_PREFER_SIZE)
7c673cae
FG
19364DUK_EXTERNAL void duk_pop(duk_context *ctx) {
19365 DUK_ASSERT_CTX_VALID(ctx);
19366 duk_pop_n(ctx, 1);
19367}
11fdf7f2
TL
19368#else
19369DUK_EXTERNAL void duk_pop(duk_context *ctx) {
19370 duk_hthread *thr = (duk_hthread *) ctx;
19371 duk_tval *tv;
19372 DUK_ASSERT_CTX_VALID(ctx);
19373
19374 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
19375 if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) {
19376 DUK_ERROR_API(thr, DUK_STR_POP_TOO_MANY);
19377 }
19378
19379 tv = --thr->valstack_top; /* tv points to element just below prev top */
19380 DUK_ASSERT(tv >= thr->valstack_bottom);
19381#ifdef DUK_USE_REFERENCE_COUNTING
19382 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
19383#else
19384 DUK_TVAL_SET_UNDEFINED(tv);
19385#endif
19386 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
19387}
19388#endif /* !DUK_USE_PREFER_SIZE */
7c673cae
FG
19389
19390DUK_EXTERNAL void duk_pop_2(duk_context *ctx) {
19391 DUK_ASSERT_CTX_VALID(ctx);
19392 duk_pop_n(ctx, 2);
19393}
19394
19395DUK_EXTERNAL void duk_pop_3(duk_context *ctx) {
19396 DUK_ASSERT_CTX_VALID(ctx);
19397 duk_pop_n(ctx, 3);
19398}
19399
19400/*
19401 * Error throwing
19402 */
19403
19404DUK_EXTERNAL void duk_throw(duk_context *ctx) {
19405 duk_hthread *thr = (duk_hthread *) ctx;
19406
19407 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
19408 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
19409 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
19410
19411 if (thr->valstack_top == thr->valstack_bottom) {
11fdf7f2 19412 DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
7c673cae
FG
19413 }
19414
19415 /* Errors are augmented when they are created, not when they are
19416 * thrown or re-thrown. The current error handler, however, runs
19417 * just before an error is thrown.
19418 */
19419
19420 /* Sync so that augmentation sees up-to-date activations, NULL
19421 * thr->ptr_curr_pc so that it's not used if side effects occur
19422 * in augmentation or longjmp handling.
19423 */
19424 duk_hthread_sync_and_null_currpc(thr);
19425
19426#if defined(DUK_USE_AUGMENT_ERROR_THROW)
19427 DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (before throw augment)", (duk_tval *) duk_get_tval(ctx, -1)));
19428 duk_err_augment_error_throw(thr);
19429#endif
19430 DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (after throw augment)", (duk_tval *) duk_get_tval(ctx, -1)));
19431
19432 duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW);
19433
19434 /* thr->heap->lj.jmpbuf_ptr is checked by duk_err_longjmp() so we don't
19435 * need to check that here. If the value is NULL, a panic occurs because
19436 * we can't return.
19437 */
19438
19439 duk_err_longjmp(thr);
19440 DUK_UNREACHABLE();
19441}
19442
19443DUK_EXTERNAL void duk_fatal(duk_context *ctx, duk_errcode_t err_code, const char *err_msg) {
19444 duk_hthread *thr = (duk_hthread *) ctx;
19445
19446 DUK_ASSERT_CTX_VALID(ctx);
19447 DUK_ASSERT(thr != NULL);
19448 DUK_ASSERT(thr->heap != NULL);
19449 DUK_ASSERT(thr->heap->fatal_func != NULL);
19450
19451 DUK_D(DUK_DPRINT("fatal error occurred, code %ld, message %s",
19452 (long) err_code, (const char *) err_msg));
19453
19454 /* fatal_func should be noreturn, but noreturn declarations on function
19455 * pointers has a very spotty support apparently so it's not currently
19456 * done.
19457 */
19458 thr->heap->fatal_func(ctx, err_code, err_msg);
19459
19460 DUK_PANIC(DUK_ERR_API_ERROR, "fatal handler returned");
19461}
19462
19463DUK_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) {
19464 DUK_ASSERT_CTX_VALID(ctx);
19465
19466 duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
19467 duk_throw(ctx);
19468}
19469
19470DUK_EXTERNAL void duk_error_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) {
19471 va_list ap;
19472
19473 DUK_ASSERT_CTX_VALID(ctx);
19474
19475 va_start(ap, fmt);
19476 duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
19477 va_end(ap);
19478 duk_throw(ctx);
19479}
19480
19481#if !defined(DUK_USE_VARIADIC_MACROS)
19482DUK_EXTERNAL void duk_error_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...) {
19483 const char *filename;
19484 duk_int_t line;
19485 va_list ap;
19486
19487 DUK_ASSERT_CTX_VALID(ctx);
19488
19489 filename = duk_api_global_filename;
19490 line = duk_api_global_line;
19491 duk_api_global_filename = NULL;
19492 duk_api_global_line = 0;
19493
19494 va_start(ap, fmt);
19495 duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
19496 va_end(ap);
19497 duk_throw(ctx);
19498}
19499#endif /* DUK_USE_VARIADIC_MACROS */
19500
19501/*
19502 * Comparison
19503 */
19504
19505DUK_EXTERNAL duk_bool_t duk_equals(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) {
19506 duk_hthread *thr = (duk_hthread *) ctx;
19507 duk_tval *tv1, *tv2;
19508
19509 DUK_ASSERT_CTX_VALID(ctx);
19510
19511 tv1 = duk_get_tval(ctx, index1);
19512 tv2 = duk_get_tval(ctx, index2);
19513 if ((tv1 == NULL) || (tv2 == NULL)) {
19514 return 0;
19515 }
19516
19517 /* Coercion may be needed, the helper handles that by pushing the
19518 * tagged values to the stack.
19519 */
19520 return duk_js_equals(thr, tv1, tv2);
19521}
19522
19523DUK_EXTERNAL duk_bool_t duk_strict_equals(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) {
19524 duk_tval *tv1, *tv2;
19525
19526 DUK_ASSERT_CTX_VALID(ctx);
19527
19528 tv1 = duk_get_tval(ctx, index1);
19529 tv2 = duk_get_tval(ctx, index2);
19530 if ((tv1 == NULL) || (tv2 == NULL)) {
19531 return 0;
19532 }
19533
19534 /* No coercions or other side effects, so safe */
19535 return duk_js_strict_equals(tv1, tv2);
19536}
19537
19538/*
19539 * instanceof
19540 */
19541
19542DUK_EXTERNAL duk_bool_t duk_instanceof(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) {
19543 duk_tval *tv1, *tv2;
19544
19545 DUK_ASSERT_CTX_VALID(ctx);
19546
19547 /* Index validation is strict, which differs from duk_equals().
19548 * The strict behavior mimics how instanceof itself works, e.g.
19549 * it is a TypeError if rval is not a -callable- object. It would
19550 * be somewhat inconsistent if rval would be allowed to be
19551 * non-existent without a TypeError.
19552 */
19553 tv1 = duk_require_tval(ctx, index1);
19554 DUK_ASSERT(tv1 != NULL);
19555 tv2 = duk_require_tval(ctx, index2);
19556 DUK_ASSERT(tv2 != NULL);
19557
19558 return duk_js_instanceof((duk_hthread *) ctx, tv1, tv2);
19559}
19560
19561/*
19562 * Lightfunc
19563 */
19564
19565DUK_INTERNAL void duk_push_lightfunc_name(duk_context *ctx, duk_tval *tv) {
19566 duk_c_function func;
19567
19568 DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv));
19569
19570 /* Lightfunc name, includes Duktape/C native function pointer, which
19571 * can often be used to locate the function from a symbol table.
19572 * The name also includes the 16-bit duk_tval flags field because it
19573 * includes the magic value. Because a single native function often
19574 * provides different functionality depending on the magic value, it
19575 * seems reasonably to include it in the name.
19576 *
19577 * On the other hand, a complicated name increases string table
19578 * pressure in low memory environments (but only when function name
19579 * is accessed).
19580 */
19581
19582 func = DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv);
19583 duk_push_sprintf(ctx, "light_");
19584 duk_push_string_funcptr(ctx, (duk_uint8_t *) &func, sizeof(func));
19585 duk_push_sprintf(ctx, "_%04x", (unsigned int) DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv));
19586 duk_concat(ctx, 3);
19587}
19588
19589DUK_INTERNAL void duk_push_lightfunc_tostring(duk_context *ctx, duk_tval *tv) {
19590 DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv));
19591
19592 duk_push_string(ctx, "function ");
19593 duk_push_lightfunc_name(ctx, tv);
11fdf7f2 19594 duk_push_string(ctx, "() {\"light\"}");
7c673cae
FG
19595 duk_concat(ctx, 3);
19596}
19597
19598/*
19599 * Function pointers
19600 *
19601 * Printing function pointers is non-portable, so we do that by hex printing
19602 * bytes from memory.
19603 */
19604
19605DUK_INTERNAL void duk_push_string_funcptr(duk_context *ctx, duk_uint8_t *ptr, duk_size_t sz) {
19606 duk_uint8_t buf[32 * 2];
19607 duk_uint8_t *p, *q;
19608 duk_small_uint_t i;
19609 duk_small_uint_t t;
19610
19611 DUK_ASSERT(sz <= 32); /* sanity limit for function pointer size */
19612
19613 p = buf;
19614#if defined(DUK_USE_INTEGER_LE)
19615 q = ptr + sz;
19616#else
19617 q = ptr;
19618#endif
19619 for (i = 0; i < sz; i++) {
19620#if defined(DUK_USE_INTEGER_LE)
19621 t = *(--q);
19622#else
19623 t = *(q++);
19624#endif
19625 *p++ = duk_lc_digits[t >> 4];
19626 *p++ = duk_lc_digits[t & 0x0f];
19627 }
19628
19629 duk_push_lstring(ctx, (const char *) buf, sz * 2);
19630}
19631
11fdf7f2
TL
19632#if !defined(DUK_USE_PARANOID_ERRORS)
19633/*
19634 * Push readable string summarizing duk_tval. The operation is side effect
19635 * free and will only throw from internal errors (e.g. out of memory).
19636 * This is used by e.g. property access code to summarize a key/base safely,
19637 * and is not intended to be fast (but small and safe).
19638 */
19639
19640#define DUK__READABLE_STRING_MAXCHARS 32
19641
19642/* String sanitizer which escapes ASCII control characters and a few other
19643 * ASCII characters, passes Unicode as is, and replaces invalid UTF-8 with
19644 * question marks. No errors are thrown for any input string, except in out
19645 * of memory situations.
19646 */
19647DUK_LOCAL void duk__push_hstring_readable_unicode(duk_context *ctx, duk_hstring *h_input) {
19648 duk_hthread *thr;
19649 const duk_uint8_t *p, *p_start, *p_end;
19650 duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH * DUK__READABLE_STRING_MAXCHARS +
19651 2 /*quotes*/ + 3 /*periods*/];
19652 duk_uint8_t *q;
19653 duk_ucodepoint_t cp;
19654 duk_small_uint_t nchars;
19655
19656 DUK_ASSERT_CTX_VALID(ctx);
19657 DUK_ASSERT(h_input != NULL);
19658 thr = (duk_hthread *) ctx;
19659
19660 p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
19661 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
19662 p = p_start;
19663 q = buf;
19664
19665 nchars = 0;
19666 *q++ = (duk_uint8_t) DUK_ASC_SINGLEQUOTE;
19667 for (;;) {
19668 if (p >= p_end) {
19669 break;
19670 }
19671 if (nchars == DUK__READABLE_STRING_MAXCHARS) {
19672 *q++ = (duk_uint8_t) DUK_ASC_PERIOD;
19673 *q++ = (duk_uint8_t) DUK_ASC_PERIOD;
19674 *q++ = (duk_uint8_t) DUK_ASC_PERIOD;
19675 break;
19676 }
19677 if (duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp)) {
19678 if (cp < 0x20 || cp == 0x7f || cp == DUK_ASC_SINGLEQUOTE || cp == DUK_ASC_BACKSLASH) {
19679 DUK_ASSERT(DUK_UNICODE_MAX_XUTF8_LENGTH >= 4); /* estimate is valid */
19680 DUK_ASSERT((cp >> 4) <= 0x0f);
19681 *q++ = (duk_uint8_t) DUK_ASC_BACKSLASH;
19682 *q++ = (duk_uint8_t) DUK_ASC_LC_X;
19683 *q++ = (duk_uint8_t) duk_lc_digits[cp >> 4];
19684 *q++ = (duk_uint8_t) duk_lc_digits[cp & 0x0f];
19685 } else {
19686 q += duk_unicode_encode_xutf8(cp, q);
19687 }
19688 } else {
19689 p++; /* advance manually */
19690 *q++ = (duk_uint8_t) DUK_ASC_QUESTION;
19691 }
19692 nchars++;
19693 }
19694 *q++ = (duk_uint8_t) DUK_ASC_SINGLEQUOTE;
19695
19696 duk_push_lstring(ctx, (const char *) buf, (duk_size_t) (q - buf));
19697}
19698
19699DUK_INTERNAL const char *duk_push_string_tval_readable(duk_context *ctx, duk_tval *tv) {
19700 duk_hthread *thr;
19701
19702 DUK_ASSERT_CTX_VALID(ctx);
19703 thr = (duk_hthread *) ctx;
19704 DUK_UNREF(thr);
19705
19706 if (tv == NULL) {
19707 duk_push_string(ctx, "none");
19708 } else {
19709 switch (DUK_TVAL_GET_TAG(tv)) {
19710 case DUK_TAG_STRING: {
19711 duk__push_hstring_readable_unicode(ctx, DUK_TVAL_GET_STRING(tv));
19712 break;
19713 }
19714 case DUK_TAG_OBJECT: {
19715 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
19716 DUK_ASSERT(h != NULL);
19717 duk_push_hobject_class_string(ctx, h);
19718 break;
19719 }
19720 case DUK_TAG_BUFFER: {
19721 /* XXX: Hex encoded, length limited buffer summary here? */
19722 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
19723 DUK_ASSERT(h != NULL);
19724 duk_push_sprintf(ctx, "[buffer:%ld]", (long) DUK_HBUFFER_GET_SIZE(h));
19725 break;
19726 }
19727 case DUK_TAG_POINTER: {
19728 /* Surround with parentheses like in JX, ensures NULL pointer
19729 * is distinguishable from null value ("(null)" vs "null").
19730 */
19731 duk_push_tval(ctx, tv);
19732 duk_push_sprintf(ctx, "(%s)", duk_to_string(ctx, -1));
19733 duk_remove(ctx, -2);
19734 break;
19735 }
19736 default: {
19737 duk_push_tval(ctx, tv);
19738 break;
19739 }
19740 }
19741 }
19742
19743 return duk_to_string(ctx, -1);
19744}
19745
19746DUK_INTERNAL const char *duk_push_string_readable(duk_context *ctx, duk_idx_t index) {
19747 DUK_ASSERT_CTX_VALID(ctx);
19748 return duk_push_string_tval_readable(ctx, duk_get_tval(ctx, index));
19749}
19750#endif /* !DUK_USE_PARANOID_ERRORS */
19751
7c673cae 19752#undef DUK__CHECK_SPACE
11fdf7f2
TL
19753#undef DUK__PACK_ARGS
19754#undef DUK__READABLE_STRING_MAXCHARS
7c673cae
FG
19755/*
19756 * String manipulation
19757 */
19758
19759/* include removed: duk_internal.h */
19760
19761DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in, duk_bool_t is_join) {
19762 duk_hthread *thr = (duk_hthread *) ctx;
19763 duk_uint_t count;
19764 duk_uint_t i;
19765 duk_size_t idx;
19766 duk_size_t len;
19767 duk_hstring *h;
19768 duk_uint8_t *buf;
19769
19770 DUK_ASSERT_CTX_VALID(ctx);
19771
19772 if (DUK_UNLIKELY(count_in <= 0)) {
19773 if (count_in < 0) {
11fdf7f2 19774 DUK_ERROR_API(thr, DUK_STR_INVALID_COUNT);
7c673cae
FG
19775 return;
19776 }
19777 DUK_ASSERT(count_in == 0);
19778 duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
19779 return;
19780 }
19781 count = (duk_uint_t) count_in;
19782
19783 if (is_join) {
19784 duk_size_t t1, t2, limit;
19785 h = duk_to_hstring(ctx, -((duk_idx_t) count) - 1);
19786 DUK_ASSERT(h != NULL);
19787
19788 /* A bit tricky overflow test, see doc/code-issues.rst. */
19789 t1 = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h);
19790 t2 = (duk_size_t) (count - 1);
19791 limit = (duk_size_t) DUK_HSTRING_MAX_BYTELEN;
19792 if (DUK_UNLIKELY(t2 != 0 && t1 > limit / t2)) {
19793 /* Combined size of separators already overflows */
19794 goto error_overflow;
19795 }
19796 len = (duk_size_t) (t1 * t2);
19797 } else {
19798 len = (duk_size_t) 0;
19799 }
19800
19801 for (i = count; i >= 1; i--) {
19802 duk_size_t new_len;
19803 duk_to_string(ctx, -((duk_idx_t) i));
19804 h = duk_require_hstring(ctx, -((duk_idx_t) i));
19805 new_len = len + (duk_size_t) DUK_HSTRING_GET_BYTELEN(h);
19806
19807 /* Impose a string maximum length, need to handle overflow
19808 * correctly.
19809 */
19810 if (new_len < len || /* wrapped */
19811 new_len > (duk_size_t) DUK_HSTRING_MAX_BYTELEN) {
19812 goto error_overflow;
19813 }
19814 len = new_len;
19815 }
19816
19817 DUK_DDD(DUK_DDDPRINT("join/concat %lu strings, total length %lu bytes",
19818 (unsigned long) count, (unsigned long) len));
19819
19820 /* use stack allocated buffer to ensure reachability in errors (e.g. intern error) */
19821 buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, len);
19822 DUK_ASSERT(buf != NULL);
19823
19824 /* [... (sep) str1 str2 ... strN buf] */
19825
19826 idx = 0;
19827 for (i = count; i >= 1; i--) {
19828 if (is_join && i != count) {
19829 h = duk_require_hstring(ctx, -((duk_idx_t) count) - 2); /* extra -1 for buffer */
19830 DUK_MEMCPY(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
19831 idx += DUK_HSTRING_GET_BYTELEN(h);
19832 }
19833 h = duk_require_hstring(ctx, -((duk_idx_t) i) - 1); /* extra -1 for buffer */
19834 DUK_MEMCPY(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
19835 idx += DUK_HSTRING_GET_BYTELEN(h);
19836 }
19837
19838 DUK_ASSERT(idx == len);
19839
19840 /* [... (sep) str1 str2 ... strN buf] */
19841
19842 /* get rid of the strings early to minimize memory use before intern */
19843
19844 if (is_join) {
19845 duk_replace(ctx, -((duk_idx_t) count) - 2); /* overwrite sep */
19846 duk_pop_n(ctx, count);
19847 } else {
19848 duk_replace(ctx, -((duk_idx_t) count) - 1); /* overwrite str1 */
19849 duk_pop_n(ctx, count-1);
19850 }
19851
19852 /* [... buf] */
19853
19854 (void) duk_to_string(ctx, -1);
19855
19856 /* [... res] */
19857 return;
19858
19859 error_overflow:
11fdf7f2 19860 DUK_ERROR_RANGE(thr, DUK_STR_CONCAT_RESULT_TOO_LONG);
7c673cae
FG
19861}
19862
19863DUK_EXTERNAL void duk_concat(duk_context *ctx, duk_idx_t count) {
19864 DUK_ASSERT_CTX_VALID(ctx);
19865
19866 duk__concat_and_join_helper(ctx, count, 0 /*is_join*/);
19867}
19868
19869DUK_EXTERNAL void duk_join(duk_context *ctx, duk_idx_t count) {
19870 DUK_ASSERT_CTX_VALID(ctx);
19871
19872 duk__concat_and_join_helper(ctx, count, 1 /*is_join*/);
19873}
19874
19875/* XXX: could map/decode be unified with duk_unicode_support.c code?
19876 * Case conversion needs also the character surroundings though.
19877 */
19878
19879DUK_EXTERNAL void duk_decode_string(duk_context *ctx, duk_idx_t index, duk_decode_char_function callback, void *udata) {
19880 duk_hthread *thr = (duk_hthread *) ctx;
19881 duk_hstring *h_input;
19882 const duk_uint8_t *p, *p_start, *p_end;
19883 duk_codepoint_t cp;
19884
19885 DUK_ASSERT_CTX_VALID(ctx);
19886
19887 h_input = duk_require_hstring(ctx, index);
19888 DUK_ASSERT(h_input != NULL);
19889
11fdf7f2 19890 p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
7c673cae
FG
19891 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
19892 p = p_start;
19893
19894 for (;;) {
19895 if (p >= p_end) {
19896 break;
19897 }
19898 cp = (int) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
19899 callback(udata, cp);
19900 }
19901}
19902
19903DUK_EXTERNAL void duk_map_string(duk_context *ctx, duk_idx_t index, duk_map_char_function callback, void *udata) {
19904 duk_hthread *thr = (duk_hthread *) ctx;
19905 duk_hstring *h_input;
19906 duk_bufwriter_ctx bw_alloc;
19907 duk_bufwriter_ctx *bw;
19908 const duk_uint8_t *p, *p_start, *p_end;
19909 duk_codepoint_t cp;
19910
19911 DUK_ASSERT_CTX_VALID(ctx);
19912
19913 index = duk_normalize_index(ctx, index);
19914
19915 h_input = duk_require_hstring(ctx, index);
19916 DUK_ASSERT(h_input != NULL);
19917
19918 bw = &bw_alloc;
19919 DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); /* reasonable output estimate */
19920
11fdf7f2 19921 p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
7c673cae
FG
19922 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
19923 p = p_start;
19924
19925 for (;;) {
19926 /* XXX: could write output in chunks with fewer ensure calls,
19927 * but relative benefit would be small here.
19928 */
19929
19930 if (p >= p_end) {
19931 break;
19932 }
19933 cp = (int) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
19934 cp = callback(udata, cp);
19935
19936 DUK_BW_WRITE_ENSURE_XUTF8(thr, bw, cp);
19937 }
19938
19939 DUK_BW_COMPACT(thr, bw);
19940 duk_to_string(ctx, -1);
19941 duk_replace(ctx, index);
19942}
19943
19944DUK_EXTERNAL void duk_substring(duk_context *ctx, duk_idx_t index, duk_size_t start_offset, duk_size_t end_offset) {
19945 duk_hthread *thr = (duk_hthread *) ctx;
19946 duk_hstring *h;
19947 duk_hstring *res;
19948 duk_size_t start_byte_offset;
19949 duk_size_t end_byte_offset;
19950
19951 DUK_ASSERT_CTX_VALID(ctx);
19952
19953 index = duk_require_normalize_index(ctx, index);
19954 h = duk_require_hstring(ctx, index);
19955 DUK_ASSERT(h != NULL);
19956
19957 if (end_offset >= DUK_HSTRING_GET_CHARLEN(h)) {
19958 end_offset = DUK_HSTRING_GET_CHARLEN(h);
19959 }
19960 if (start_offset > end_offset) {
19961 start_offset = end_offset;
19962 }
19963
19964 DUK_ASSERT_DISABLE(start_offset >= 0);
19965 DUK_ASSERT(start_offset <= end_offset && start_offset <= DUK_HSTRING_GET_CHARLEN(h));
19966 DUK_ASSERT_DISABLE(end_offset >= 0);
19967 DUK_ASSERT(end_offset >= start_offset && end_offset <= DUK_HSTRING_GET_CHARLEN(h));
19968
19969 /* guaranteed by string limits */
19970 DUK_ASSERT(start_offset <= DUK_UINT32_MAX);
19971 DUK_ASSERT(end_offset <= DUK_UINT32_MAX);
19972
19973 start_byte_offset = (duk_size_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint_fast32_t) start_offset);
19974 end_byte_offset = (duk_size_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint_fast32_t) end_offset);
19975
19976 DUK_ASSERT(end_byte_offset >= start_byte_offset);
19977 DUK_ASSERT(end_byte_offset - start_byte_offset <= DUK_UINT32_MAX); /* guaranteed by string limits */
19978
19979 /* no size check is necessary */
19980 res = duk_heap_string_intern_checked(thr,
19981 DUK_HSTRING_GET_DATA(h) + start_byte_offset,
19982 (duk_uint32_t) (end_byte_offset - start_byte_offset));
19983
19984 duk_push_hstring(ctx, res);
19985 duk_replace(ctx, index);
19986}
19987
19988/* XXX: this is quite clunky. Add Unicode helpers to scan backwards and
19989 * forwards with a callback to process codepoints?
19990 */
19991DUK_EXTERNAL void duk_trim(duk_context *ctx, duk_idx_t index) {
19992 duk_hthread *thr = (duk_hthread *) ctx;
19993 duk_hstring *h;
19994 const duk_uint8_t *p, *p_start, *p_end, *p_tmp1, *p_tmp2; /* pointers for scanning */
19995 const duk_uint8_t *q_start, *q_end; /* start (incl) and end (excl) of trimmed part */
19996 duk_codepoint_t cp;
19997
19998 DUK_ASSERT_CTX_VALID(ctx);
19999
20000 index = duk_require_normalize_index(ctx, index);
20001 h = duk_require_hstring(ctx, index);
20002 DUK_ASSERT(h != NULL);
20003
20004 p_start = DUK_HSTRING_GET_DATA(h);
20005 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h);
20006
20007 p = p_start;
20008 while (p < p_end) {
20009 p_tmp1 = p;
20010 cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p_tmp1, p_start, p_end);
20011 if (!(duk_unicode_is_whitespace(cp) || duk_unicode_is_line_terminator(cp))) {
20012 break;
20013 }
20014 p = p_tmp1;
20015 }
20016 q_start = p;
20017 if (p == p_end) {
20018 /* entire string is whitespace */
20019 q_end = p;
20020 goto scan_done;
20021 }
20022
20023 p = p_end;
20024 while (p > p_start) {
20025 p_tmp1 = p;
20026 while (p > p_start) {
20027 p--;
20028 if (((*p) & 0xc0) != 0x80) {
20029 break;
20030 }
20031 }
20032 p_tmp2 = p;
20033
20034 cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p_tmp2, p_start, p_end);
20035 if (!(duk_unicode_is_whitespace(cp) || duk_unicode_is_line_terminator(cp))) {
20036 p = p_tmp1;
20037 break;
20038 }
20039 }
20040 q_end = p;
20041
20042 scan_done:
20043 /* This may happen when forward and backward scanning disagree
20044 * (possible for non-extended-UTF-8 strings).
20045 */
20046 if (q_end < q_start) {
20047 q_end = q_start;
20048 }
20049
20050 DUK_ASSERT(q_start >= p_start && q_start <= p_end);
20051 DUK_ASSERT(q_end >= p_start && q_end <= p_end);
20052 DUK_ASSERT(q_end >= q_start);
20053
20054 DUK_DDD(DUK_DDDPRINT("trim: p_start=%p, p_end=%p, q_start=%p, q_end=%p",
11fdf7f2
TL
20055 (const void *) p_start, (const void *) p_end,
20056 (const void *) q_start, (const void *) q_end));
7c673cae
FG
20057
20058 if (q_start == p_start && q_end == p_end) {
20059 DUK_DDD(DUK_DDDPRINT("nothing was trimmed: avoid interning (hashing etc)"));
20060 return;
20061 }
20062
20063 duk_push_lstring(ctx, (const char *) q_start, (duk_size_t) (q_end - q_start));
20064 duk_replace(ctx, index);
20065}
20066
20067DUK_EXTERNAL duk_codepoint_t duk_char_code_at(duk_context *ctx, duk_idx_t index, duk_size_t char_offset) {
20068 duk_hthread *thr = (duk_hthread *) ctx;
20069 duk_hstring *h;
20070 duk_ucodepoint_t cp;
20071
20072 DUK_ASSERT_CTX_VALID(ctx);
20073
20074 h = duk_require_hstring(ctx, index);
20075 DUK_ASSERT(h != NULL);
20076
20077 DUK_ASSERT_DISABLE(char_offset >= 0); /* always true, arg is unsigned */
20078 if (char_offset >= DUK_HSTRING_GET_CHARLEN(h)) {
20079 return 0;
20080 }
20081
20082 DUK_ASSERT(char_offset <= DUK_UINT_MAX); /* guaranteed by string limits */
20083 cp = duk_hstring_char_code_at_raw(thr, h, (duk_uint_t) char_offset);
20084 return (duk_codepoint_t) cp;
20085}
7c673cae
FG
20086/*
20087 * Variable access
20088 */
20089
20090/* include removed: duk_internal.h */
20091
20092DUK_EXTERNAL void duk_get_var(duk_context *ctx) {
20093 duk_hthread *thr = (duk_hthread *) ctx;
20094 duk_activation *act;
20095 duk_hstring *h_varname;
20096 duk_small_int_t throw_flag = 1; /* always throw ReferenceError for unresolvable */
20097
20098 DUK_ASSERT_CTX_VALID(ctx);
20099
20100 h_varname = duk_require_hstring(ctx, -1); /* XXX: tostring? */
20101 DUK_ASSERT(h_varname != NULL);
20102
20103 act = duk_hthread_get_current_activation(thr);
20104 if (act) {
20105 (void) duk_js_getvar_activation(thr, act, h_varname, throw_flag); /* -> [ ... varname val this ] */
20106 } else {
20107 /* Outside any activation -> look up from global. */
20108 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL);
20109 (void) duk_js_getvar_envrec(thr, thr->builtins[DUK_BIDX_GLOBAL_ENV], h_varname, throw_flag);
20110 }
20111
20112 /* [ ... varname val this ] (because throw_flag == 1, always resolved) */
20113
20114 duk_pop(ctx);
20115 duk_remove(ctx, -2);
20116
20117 /* [ ... val ] */
20118
20119 /* Return value would be pointless: because throw_flag==1, we always
20120 * throw if the identifier doesn't resolve.
20121 */
20122 return;
20123}
20124
20125DUK_EXTERNAL void duk_put_var(duk_context *ctx) {
20126 duk_hthread *thr = (duk_hthread *) ctx;
20127 duk_activation *act;
20128 duk_hstring *h_varname;
20129 duk_tval *tv_val;
20130 duk_small_int_t throw_flag;
20131
20132 DUK_ASSERT_CTX_VALID(ctx);
20133
20134 h_varname = duk_require_hstring(ctx, -2); /* XXX: tostring? */
20135 DUK_ASSERT(h_varname != NULL);
20136
20137 tv_val = duk_require_tval(ctx, -1);
20138
20139 throw_flag = duk_is_strict_call(ctx);
20140
20141 act = duk_hthread_get_current_activation(thr);
20142 if (act) {
20143 duk_js_putvar_activation(thr, act, h_varname, tv_val, throw_flag); /* -> [ ... varname val this ] */
20144 } else {
20145 /* Outside any activation -> put to global. */
20146 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL);
20147 duk_js_putvar_envrec(thr, thr->builtins[DUK_BIDX_GLOBAL_ENV], h_varname, tv_val, throw_flag);
20148 }
20149
20150 /* [ ... varname val ] */
20151
20152 duk_pop_2(ctx);
20153
20154 /* [ ... ] */
20155
20156 return;
20157}
20158
20159DUK_EXTERNAL duk_bool_t duk_del_var(duk_context *ctx) {
20160 DUK_ASSERT_CTX_VALID(ctx);
20161
11fdf7f2 20162 DUK_ERROR_UNIMPLEMENTED_DEFMSG((duk_hthread *) ctx);
7c673cae
FG
20163 return 0;
20164}
20165
20166DUK_EXTERNAL duk_bool_t duk_has_var(duk_context *ctx) {
20167 DUK_ASSERT_CTX_VALID(ctx);
20168
11fdf7f2 20169 DUK_ERROR_UNIMPLEMENTED_DEFMSG((duk_hthread *) ctx);
7c673cae
FG
20170 return 0;
20171}
7c673cae
FG
20172/*
20173 * Array built-ins
20174 *
20175 * Note that most Array built-ins are intentionally generic and work even
20176 * when the 'this' binding is not an Array instance. To ensure this,
20177 * Array algorithms do not assume "magical" Array behavior for the "length"
20178 * property, for instance.
20179 *
20180 * XXX: the "Throw" flag should be set for (almost?) all [[Put]] and
20181 * [[Delete]] operations, but it's currently false throughout. Go through
20182 * all put/delete cases and check throw flag use. Need a new API primitive
20183 * which allows throws flag to be specified.
20184 *
20185 * XXX: array lengths above 2G won't work reliably. There are many places
20186 * where one needs a full signed 32-bit range ([-0xffffffff, 0xffffffff],
20187 * i.e. -33- bits). Although array 'length' cannot be written to be outside
20188 * the unsigned 32-bit range (E5.1 Section 15.4.5.1 throws a RangeError if so)
20189 * some intermediate values may be above 0xffffffff and this may not be always
20190 * correctly handled now (duk_uint32_t is not enough for all algorithms).
20191 *
20192 * For instance, push() can legitimately write entries beyond length 0xffffffff
20193 * and cause a RangeError only at the end. To do this properly, the current
20194 * push() implementation tracks the array index using a 'double' instead of a
20195 * duk_uint32_t (which is somewhat awkward). See test-bi-array-push-maxlen.js.
20196 *
20197 * On using "put" vs. "def" prop
20198 * =============================
20199 *
20200 * Code below must be careful to use the appropriate primitive as it matters
20201 * for compliance. When using "put" there may be inherited properties in
20202 * Array.prototype which cause side effects when values are written. When
20203 * using "define" there are no such side effects, and many test262 test cases
20204 * check for this (for real world code, such side effects are very rare).
20205 * Both "put" and "define" are used in the E5.1 specification; as a rule,
20206 * "put" is used when modifying an existing array (or a non-array 'this'
20207 * binding) and "define" for setting values into a fresh result array.
20208 *
20209 * Also note that Array instance 'length' should be writable, but not
20210 * enumerable and definitely not configurable: even Duktape code internally
20211 * assumes that an Array instance will always have a 'length' property.
20212 * Preventing deletion of the property is critical.
20213 */
20214
20215/* include removed: duk_internal.h */
20216
20217/* Perform an intermediate join when this many elements have been pushed
20218 * on the value stack.
20219 */
20220#define DUK__ARRAY_MID_JOIN_LIMIT 4096
20221
20222/* Shared entry code for many Array built-ins. Note that length is left
20223 * on stack (it could be popped, but that's not necessary).
20224 */
20225DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32(duk_context *ctx) {
20226 duk_uint32_t len;
20227
20228 (void) duk_push_this_coercible_to_object(ctx);
20229 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LENGTH);
20230 len = duk_to_uint32(ctx, -1);
20231
20232 /* -> [ ... ToObject(this) ToUint32(length) ] */
20233 return len;
20234}
20235
20236DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32_limited(duk_context *ctx) {
20237 /* Range limited to [0, 0x7fffffff] range, i.e. range that can be
20238 * represented with duk_int32_t. Use this when the method doesn't
20239 * handle the full 32-bit unsigned range correctly.
20240 */
20241 duk_uint32_t ret = duk__push_this_obj_len_u32(ctx);
20242 if (DUK_UNLIKELY(ret >= 0x80000000UL)) {
11fdf7f2 20243 DUK_ERROR_RANGE((duk_hthread *) ctx, DUK_STR_ARRAY_LENGTH_OVER_2G);
7c673cae
FG
20244 }
20245 return ret;
20246}
20247
20248/*
20249 * Constructor
20250 */
20251
20252DUK_INTERNAL duk_ret_t duk_bi_array_constructor(duk_context *ctx) {
20253 duk_idx_t nargs;
20254 duk_double_t d;
20255 duk_uint32_t len;
20256 duk_idx_t i;
20257
20258 nargs = duk_get_top(ctx);
20259 duk_push_array(ctx);
20260
20261 if (nargs == 1 && duk_is_number(ctx, 0)) {
20262 /* XXX: expensive check (also shared elsewhere - so add a shared internal API call?) */
20263 d = duk_get_number(ctx, 0);
20264 len = duk_to_uint32(ctx, 0);
20265 if (((duk_double_t) len) != d) {
20266 return DUK_RET_RANGE_ERROR;
20267 }
20268
20269 /* XXX: if 'len' is low, may want to ensure array part is kept:
20270 * the caller is likely to want a dense array.
20271 */
20272 duk_push_u32(ctx, len);
20273 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); /* [ ToUint32(len) array ToUint32(len) ] -> [ ToUint32(len) array ] */
20274 return 1;
20275 }
20276
20277 /* XXX: optimize by creating array into correct size directly, and
20278 * operating on the array part directly; values can be memcpy()'d from
20279 * value stack directly as long as refcounts are increased.
20280 */
20281 for (i = 0; i < nargs; i++) {
20282 duk_dup(ctx, i);
20283 duk_xdef_prop_index_wec(ctx, -2, (duk_uarridx_t) i);
20284 }
20285
20286 duk_push_u32(ctx, (duk_uint32_t) nargs);
20287 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
20288 return 1;
20289}
20290
20291/*
20292 * isArray()
20293 */
20294
20295DUK_INTERNAL duk_ret_t duk_bi_array_constructor_is_array(duk_context *ctx) {
20296 duk_hobject *h;
20297
20298 h = duk_get_hobject_with_class(ctx, 0, DUK_HOBJECT_CLASS_ARRAY);
20299 duk_push_boolean(ctx, (h != NULL));
20300 return 1;
20301}
20302
20303/*
20304 * toString()
20305 */
20306
20307DUK_INTERNAL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx) {
20308 (void) duk_push_this_coercible_to_object(ctx);
20309 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_JOIN);
20310
20311 /* [ ... this func ] */
20312 if (!duk_is_callable(ctx, -1)) {
20313 /* Fall back to the initial (original) Object.toString(). We don't
20314 * currently have pointers to the built-in functions, only the top
20315 * level global objects (like "Array") so this is now done in a bit
20316 * of a hacky manner. It would be cleaner to push the (original)
20317 * function and use duk_call_method().
20318 */
20319
20320 /* XXX: 'this' will be ToObject() coerced twice, which is incorrect
20321 * but should have no visible side effects.
20322 */
20323 DUK_DDD(DUK_DDDPRINT("this.join is not callable, fall back to (original) Object.toString"));
20324 duk_set_top(ctx, 0);
20325 return duk_bi_object_prototype_to_string(ctx); /* has access to 'this' binding */
20326 }
20327
20328 /* [ ... this func ] */
20329
20330 duk_insert(ctx, -2);
20331
20332 /* [ ... func this ] */
20333
20334 DUK_DDD(DUK_DDDPRINT("calling: func=%!iT, this=%!iT",
20335 (duk_tval *) duk_get_tval(ctx, -2),
20336 (duk_tval *) duk_get_tval(ctx, -1)));
20337 duk_call_method(ctx, 0);
20338
20339 return 1;
20340}
20341
20342/*
20343 * concat()
20344 */
20345
20346DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx) {
20347 duk_idx_t i, n;
20348 duk_uarridx_t idx, idx_last;
20349 duk_uarridx_t j, len;
20350 duk_hobject *h;
20351
20352 /* XXX: the insert here is a bit expensive if there are a lot of items.
20353 * It could also be special cased in the outermost for loop quite easily
20354 * (as the element is dup()'d anyway).
20355 */
20356
20357 (void) duk_push_this_coercible_to_object(ctx);
20358 duk_insert(ctx, 0);
20359 n = duk_get_top(ctx);
20360 duk_push_array(ctx); /* -> [ ToObject(this) item1 ... itemN arr ] */
20361
20362 /* NOTE: The Array special behaviors are NOT invoked by duk_xdef_prop_index()
20363 * (which differs from the official algorithm). If no error is thrown, this
20364 * doesn't matter as the length is updated at the end. However, if an error
20365 * is thrown, the length will be unset. That shouldn't matter because the
20366 * caller won't get a reference to the intermediate value.
20367 */
20368
20369 idx = 0;
20370 idx_last = 0;
20371 for (i = 0; i < n; i++) {
20372 DUK_ASSERT_TOP(ctx, n + 1);
20373
20374 /* [ ToObject(this) item1 ... itemN arr ] */
20375
20376 duk_dup(ctx, i);
20377 h = duk_get_hobject_with_class(ctx, -1, DUK_HOBJECT_CLASS_ARRAY);
20378 if (!h) {
20379 duk_xdef_prop_index_wec(ctx, -2, idx++);
20380 idx_last = idx;
20381 continue;
20382 }
20383
20384 /* [ ToObject(this) item1 ... itemN arr item(i) ] */
20385
20386 /* XXX: an array can have length higher than 32 bits; this is not handled
20387 * correctly now.
20388 */
20389 len = (duk_uarridx_t) duk_get_length(ctx, -1);
20390 for (j = 0; j < len; j++) {
20391 if (duk_get_prop_index(ctx, -1, j)) {
20392 /* [ ToObject(this) item1 ... itemN arr item(i) item(i)[j] ] */
20393 duk_xdef_prop_index_wec(ctx, -3, idx++);
20394 idx_last = idx;
20395 } else {
20396 idx++;
20397 duk_pop(ctx);
20398#if defined(DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER)
20399 /* According to E5.1 Section 15.4.4.4 nonexistent trailing
20400 * elements do not affect 'length' of the result. Test262
20401 * and other engines disagree, so update idx_last here too.
20402 */
20403 idx_last = idx;
20404#else
20405 /* Strict standard behavior, ignore trailing elements for
20406 * result 'length'.
20407 */
20408#endif
20409 }
20410 }
20411 duk_pop(ctx);
20412 }
20413
20414 /* The E5.1 Section 15.4.4.4 algorithm doesn't set the length explicitly
20415 * in the end, but because we're operating with an internal value which
20416 * is known to be an array, this should be equivalent.
20417 */
20418 duk_push_uarridx(ctx, idx_last);
20419 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
20420
20421 DUK_ASSERT_TOP(ctx, n + 1);
20422 return 1;
20423}
20424
20425/*
20426 * join(), toLocaleString()
20427 *
20428 * Note: checking valstack is necessary, but only in the per-element loop.
20429 *
20430 * Note: the trivial approach of pushing all the elements on the value stack
20431 * and then calling duk_join() fails when the array contains a large number
20432 * of elements. This problem can't be offloaded to duk_join() because the
20433 * elements to join must be handled here and have special handling. Current
20434 * approach is to do intermediate joins with very large number of elements.
20435 * There is no fancy handling; the prefix gets re-joined multiple times.
20436 */
20437
20438DUK_INTERNAL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx) {
20439 duk_uint32_t len, count;
20440 duk_uint32_t idx;
20441 duk_small_int_t to_locale_string = duk_get_current_magic(ctx);
20442 duk_idx_t valstack_required;
20443
20444 /* For join(), nargs is 1. For toLocaleString(), nargs is 0 and
20445 * setting the top essentially pushes an undefined to the stack,
20446 * thus defaulting to a comma separator.
20447 */
20448 duk_set_top(ctx, 1);
20449 if (duk_is_undefined(ctx, 0)) {
20450 duk_pop(ctx);
20451 duk_push_hstring_stridx(ctx, DUK_STRIDX_COMMA);
20452 } else {
20453 duk_to_string(ctx, 0);
20454 }
20455
20456 len = duk__push_this_obj_len_u32(ctx);
20457
20458 /* [ sep ToObject(this) len ] */
20459
20460 DUK_DDD(DUK_DDDPRINT("sep=%!T, this=%!T, len=%lu",
20461 (duk_tval *) duk_get_tval(ctx, 0),
20462 (duk_tval *) duk_get_tval(ctx, 1),
20463 (unsigned long) len));
20464
20465 /* The extra (+4) is tight. */
20466 valstack_required = (len >= DUK__ARRAY_MID_JOIN_LIMIT ?
20467 DUK__ARRAY_MID_JOIN_LIMIT : len) + 4;
20468 duk_require_stack(ctx, valstack_required);
20469
20470 duk_dup(ctx, 0);
20471
20472 /* [ sep ToObject(this) len sep ] */
20473
20474 count = 0;
20475 idx = 0;
20476 for (;;) {
20477 if (count >= DUK__ARRAY_MID_JOIN_LIMIT || /* intermediate join to avoid valstack overflow */
20478 idx >= len) { /* end of loop (careful with len==0) */
20479 /* [ sep ToObject(this) len sep str0 ... str(count-1) ] */
20480 DUK_DDD(DUK_DDDPRINT("mid/final join, count=%ld, idx=%ld, len=%ld",
20481 (long) count, (long) idx, (long) len));
20482 duk_join(ctx, (duk_idx_t) count); /* -> [ sep ToObject(this) len str ] */
20483 duk_dup(ctx, 0); /* -> [ sep ToObject(this) len str sep ] */
20484 duk_insert(ctx, -2); /* -> [ sep ToObject(this) len sep str ] */
20485 count = 1;
20486 }
20487 if (idx >= len) {
20488 /* if true, the stack already contains the final result */
20489 break;
20490 }
20491
20492 duk_get_prop_index(ctx, 1, (duk_uarridx_t) idx);
20493 if (duk_is_null_or_undefined(ctx, -1)) {
20494 duk_pop(ctx);
20495 duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
20496 } else {
20497 if (to_locale_string) {
20498 duk_to_object(ctx, -1);
20499 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_TO_LOCALE_STRING);
20500 duk_insert(ctx, -2); /* -> [ ... toLocaleString ToObject(val) ] */
20501 duk_call_method(ctx, 0);
20502 duk_to_string(ctx, -1);
20503 } else {
20504 duk_to_string(ctx, -1);
20505 }
20506 }
20507
20508 count++;
20509 idx++;
20510 }
20511
20512 /* [ sep ToObject(this) len sep result ] */
20513
20514 return 1;
20515}
20516
20517/*
20518 * pop(), push()
20519 */
20520
20521DUK_INTERNAL duk_ret_t duk_bi_array_prototype_pop(duk_context *ctx) {
20522 duk_uint32_t len;
20523 duk_uint32_t idx;
20524
20525 DUK_ASSERT_TOP(ctx, 0);
20526 len = duk__push_this_obj_len_u32(ctx);
20527 if (len == 0) {
20528 duk_push_int(ctx, 0);
20529 duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH);
20530 return 0;
20531 }
20532 idx = len - 1;
20533
20534 duk_get_prop_index(ctx, 0, (duk_uarridx_t) idx);
20535 duk_del_prop_index(ctx, 0, (duk_uarridx_t) idx);
20536 duk_push_u32(ctx, idx);
20537 duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH);
20538 return 1;
20539}
20540
20541DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx) {
20542 /* Note: 'this' is not necessarily an Array object. The push()
20543 * algorithm is supposed to work for other kinds of objects too,
20544 * so the algorithm has e.g. an explicit update for the 'length'
20545 * property which is normally "magical" in arrays.
20546 */
20547
20548 duk_uint32_t len;
20549 duk_idx_t i, n;
20550
20551 n = duk_get_top(ctx);
20552 len = duk__push_this_obj_len_u32(ctx);
20553
20554 /* [ arg1 ... argN obj length ] */
20555
20556 /* Technically Array.prototype.push() can create an Array with length
20557 * longer than 2^32-1, i.e. outside the 32-bit range. The final length
20558 * is *not* wrapped to 32 bits in the specification.
20559 *
20560 * This implementation tracks length with a uint32 because it's much
20561 * more practical.
20562 *
20563 * See: test-bi-array-push-maxlen.js.
20564 */
20565
20566 if (len + (duk_uint32_t) n < len) {
20567 DUK_D(DUK_DPRINT("Array.prototype.push() would go beyond 32-bit length, throw"));
20568 return DUK_RET_RANGE_ERROR;
20569 }
20570
20571 for (i = 0; i < n; i++) {
20572 duk_dup(ctx, i);
20573 duk_put_prop_index(ctx, -3, len + i);
20574 }
20575 len += n;
20576
20577 duk_push_u32(ctx, len);
20578 duk_dup_top(ctx);
20579 duk_put_prop_stridx(ctx, -4, DUK_STRIDX_LENGTH);
20580
20581 /* [ arg1 ... argN obj length new_length ] */
20582 return 1;
20583}
20584
20585/*
20586 * sort()
20587 *
20588 * Currently qsort with random pivot. This is now really, really slow,
20589 * because there is no fast path for array parts.
20590 *
20591 * Signed indices are used because qsort() leaves and degenerate cases
20592 * may use a negative offset.
20593 */
20594
20595DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_context *ctx, duk_int_t idx1, duk_int_t idx2) {
20596 duk_bool_t have1, have2;
20597 duk_bool_t undef1, undef2;
20598 duk_small_int_t ret;
20599 duk_idx_t idx_obj = 1; /* fixed offsets in valstack */
20600 duk_idx_t idx_fn = 0;
20601 duk_hstring *h1, *h2;
20602
20603 /* Fast exit if indices are identical. This is valid for a non-existent property,
20604 * for an undefined value, and almost always for ToString() coerced comparison of
20605 * arbitrary values (corner cases where this is not the case include e.g. a an
20606 * object with varying ToString() coercion).
20607 *
20608 * The specification does not prohibit "caching" of values read from the array, so
20609 * assuming equality for comparing an index with itself falls into the category of
20610 * "caching".
20611 *
20612 * Also, compareFn may be inconsistent, so skipping a call to compareFn here may
20613 * have an effect on the final result. The specification does not require any
20614 * specific behavior for inconsistent compare functions, so again, this fast path
20615 * is OK.
20616 */
20617
20618 if (idx1 == idx2) {
20619 DUK_DDD(DUK_DDDPRINT("duk__array_sort_compare: idx1=%ld, idx2=%ld -> indices identical, quick exit",
20620 (long) idx1, (long) idx2));
20621 return 0;
20622 }
20623
20624 have1 = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) idx1);
20625 have2 = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) idx2);
20626
20627 DUK_DDD(DUK_DDDPRINT("duk__array_sort_compare: idx1=%ld, idx2=%ld, have1=%ld, have2=%ld, val1=%!T, val2=%!T",
20628 (long) idx1, (long) idx2, (long) have1, (long) have2,
20629 (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1)));
20630
20631 if (have1) {
20632 if (have2) {
20633 ;
20634 } else {
20635 ret = -1;
20636 goto pop_ret;
20637 }
20638 } else {
20639 if (have2) {
20640 ret = 1;
20641 goto pop_ret;
20642 } else {
20643 ret = 0;
20644 goto pop_ret;
20645 }
20646 }
20647
20648 undef1 = duk_is_undefined(ctx, -2);
20649 undef2 = duk_is_undefined(ctx, -1);
20650 if (undef1) {
20651 if (undef2) {
20652 ret = 0;
20653 goto pop_ret;
20654 } else {
20655 ret = 1;
20656 goto pop_ret;
20657 }
20658 } else {
20659 if (undef2) {
20660 ret = -1;
20661 goto pop_ret;
20662 } else {
20663 ;
20664 }
20665 }
20666
20667 if (!duk_is_undefined(ctx, idx_fn)) {
20668 duk_double_t d;
20669
20670 /* no need to check callable; duk_call() will do that */
20671 duk_dup(ctx, idx_fn); /* -> [ ... x y fn ] */
20672 duk_insert(ctx, -3); /* -> [ ... fn x y ] */
20673 duk_call(ctx, 2); /* -> [ ... res ] */
20674
20675 /* The specification is a bit vague what to do if the return
20676 * value is not a number. Other implementations seem to
20677 * tolerate non-numbers but e.g. V8 won't apparently do a
20678 * ToNumber().
20679 */
20680
20681 /* XXX: best behavior for real world compatibility? */
20682
20683 d = duk_to_number(ctx, -1);
20684 if (d < 0.0) {
20685 ret = -1;
20686 } else if (d > 0.0) {
20687 ret = 1;
20688 } else {
20689 ret = 0;
20690 }
20691
20692 duk_pop(ctx);
20693 DUK_DDD(DUK_DDDPRINT("-> result %ld (from comparefn, after coercion)", (long) ret));
20694 return ret;
20695 }
20696
20697 /* string compare is the default (a bit oddly) */
20698
20699 h1 = duk_to_hstring(ctx, -2);
20700 h2 = duk_to_hstring(ctx, -1);
20701 DUK_ASSERT(h1 != NULL);
20702 DUK_ASSERT(h2 != NULL);
20703
20704 ret = duk_js_string_compare(h1, h2); /* retval is directly usable */
20705 goto pop_ret;
20706
20707 pop_ret:
20708 duk_pop_2(ctx);
20709 DUK_DDD(DUK_DDDPRINT("-> result %ld", (long) ret));
20710 return ret;
20711}
20712
20713DUK_LOCAL void duk__array_sort_swap(duk_context *ctx, duk_int_t l, duk_int_t r) {
20714 duk_bool_t have_l, have_r;
20715 duk_idx_t idx_obj = 1; /* fixed offset in valstack */
20716
20717 if (l == r) {
20718 return;
20719 }
20720
20721 /* swap elements; deal with non-existent elements correctly */
20722 have_l = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) l);
20723 have_r = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) r);
20724
20725 if (have_r) {
20726 /* right exists, [[Put]] regardless whether or not left exists */
20727 duk_put_prop_index(ctx, idx_obj, (duk_uarridx_t) l);
20728 } else {
20729 duk_del_prop_index(ctx, idx_obj, (duk_uarridx_t) l);
20730 duk_pop(ctx);
20731 }
20732
20733 if (have_l) {
20734 duk_put_prop_index(ctx, idx_obj, (duk_uarridx_t) r);
20735 } else {
20736 duk_del_prop_index(ctx, idx_obj, (duk_uarridx_t) r);
20737 duk_pop(ctx);
20738 }
20739}
20740
20741#if defined(DUK_USE_DDDPRINT)
20742/* Debug print which visualizes the qsort partitioning process. */
20743DUK_LOCAL void duk__debuglog_qsort_state(duk_context *ctx, duk_int_t lo, duk_int_t hi, duk_int_t pivot) {
20744 char buf[4096];
20745 char *ptr = buf;
20746 duk_int_t i, n;
20747 n = (duk_int_t) duk_get_length(ctx, 1);
20748 if (n > 4000) {
20749 n = 4000;
20750 }
20751 *ptr++ = '[';
20752 for (i = 0; i < n; i++) {
20753 if (i == pivot) {
20754 *ptr++ = '|';
20755 } else if (i == lo) {
20756 *ptr++ = '<';
20757 } else if (i == hi) {
20758 *ptr++ = '>';
20759 } else if (i >= lo && i <= hi) {
20760 *ptr++ = '-';
20761 } else {
20762 *ptr++ = ' ';
20763 }
20764 }
20765 *ptr++ = ']';
20766 *ptr++ = '\0';
20767
20768 DUK_DDD(DUK_DDDPRINT("%s (lo=%ld, hi=%ld, pivot=%ld)",
20769 (const char *) buf, (long) lo, (long) hi, (long) pivot));
20770}
20771#endif
20772
20773DUK_LOCAL void duk__array_qsort(duk_context *ctx, duk_int_t lo, duk_int_t hi) {
20774 duk_hthread *thr = (duk_hthread *) ctx;
20775 duk_int_t p, l, r;
20776
20777 /* The lo/hi indices may be crossed and hi < 0 is possible at entry. */
20778
20779 DUK_DDD(DUK_DDDPRINT("duk__array_qsort: lo=%ld, hi=%ld, obj=%!T",
20780 (long) lo, (long) hi, (duk_tval *) duk_get_tval(ctx, 1)));
20781
20782 DUK_ASSERT_TOP(ctx, 3);
20783
20784 /* In some cases it may be that lo > hi, or hi < 0; these
20785 * degenerate cases happen e.g. for empty arrays, and in
20786 * recursion leaves.
20787 */
20788
20789 /* trivial cases */
20790 if (hi - lo < 1) {
20791 DUK_DDD(DUK_DDDPRINT("degenerate case, return immediately"));
20792 return;
20793 }
20794 DUK_ASSERT(hi > lo);
20795 DUK_ASSERT(hi - lo + 1 >= 2);
20796
20797 /* randomized pivot selection */
20798 p = lo + (duk_util_tinyrandom_get_bits(thr, 30) % (hi - lo + 1)); /* rnd in [lo,hi] */
20799 DUK_ASSERT(p >= lo && p <= hi);
20800 DUK_DDD(DUK_DDDPRINT("lo=%ld, hi=%ld, chose pivot p=%ld",
20801 (long) lo, (long) hi, (long) p));
20802
20803 /* move pivot out of the way */
20804 duk__array_sort_swap(ctx, p, lo);
20805 p = lo;
20806 DUK_DDD(DUK_DDDPRINT("pivot moved out of the way: %!T", (duk_tval *) duk_get_tval(ctx, 1)));
20807
20808 l = lo + 1;
20809 r = hi;
20810 for (;;) {
20811 /* find elements to swap */
20812 for (;;) {
20813 DUK_DDD(DUK_DDDPRINT("left scan: l=%ld, r=%ld, p=%ld",
20814 (long) l, (long) r, (long) p));
20815 if (l >= hi) {
20816 break;
20817 }
20818 if (duk__array_sort_compare(ctx, l, p) >= 0) { /* !(l < p) */
20819 break;
20820 }
20821 l++;
20822 }
20823 for (;;) {
20824 DUK_DDD(DUK_DDDPRINT("right scan: l=%ld, r=%ld, p=%ld",
20825 (long) l, (long) r, (long) p));
20826 if (r <= lo) {
20827 break;
20828 }
20829 if (duk__array_sort_compare(ctx, p, r) >= 0) { /* !(p < r) */
20830 break;
20831 }
20832 r--;
20833 }
20834 if (l >= r) {
20835 goto done;
20836 }
20837 DUK_ASSERT(l < r);
20838
20839 DUK_DDD(DUK_DDDPRINT("swap %ld and %ld", (long) l, (long) r));
20840
20841 duk__array_sort_swap(ctx, l, r);
20842
20843 DUK_DDD(DUK_DDDPRINT("after swap: %!T", (duk_tval *) duk_get_tval(ctx, 1)));
20844 l++;
20845 r--;
20846 }
20847 done:
20848 /* Note that 'l' and 'r' may cross, i.e. r < l */
20849 DUK_ASSERT(l >= lo && l <= hi);
20850 DUK_ASSERT(r >= lo && r <= hi);
20851
20852 /* XXX: there's no explicit recursion bound here now. For the average
20853 * qsort recursion depth O(log n) that's not really necessary: e.g. for
20854 * 2**32 recursion depth would be about 32 which is OK. However, qsort
20855 * worst case recursion depth is O(n) which may be a problem.
20856 */
20857
20858 /* move pivot to its final place */
20859 DUK_DDD(DUK_DDDPRINT("before final pivot swap: %!T", (duk_tval *) duk_get_tval(ctx, 1)));
20860 duk__array_sort_swap(ctx, lo, r);
20861
20862#if defined(DUK_USE_DDDPRINT)
20863 duk__debuglog_qsort_state(ctx, lo, hi, r);
20864#endif
20865
20866 DUK_DDD(DUK_DDDPRINT("recurse: pivot=%ld, obj=%!T", (long) r, (duk_tval *) duk_get_tval(ctx, 1)));
20867 duk__array_qsort(ctx, lo, r - 1);
20868 duk__array_qsort(ctx, r + 1, hi);
20869}
20870
20871DUK_INTERNAL duk_ret_t duk_bi_array_prototype_sort(duk_context *ctx) {
20872 duk_uint32_t len;
20873
20874 /* XXX: len >= 0x80000000 won't work below because a signed type
20875 * is needed by qsort.
20876 */
20877 len = duk__push_this_obj_len_u32_limited(ctx);
20878
20879 /* stack[0] = compareFn
20880 * stack[1] = ToObject(this)
20881 * stack[2] = ToUint32(length)
20882 */
20883
20884 if (len > 0) {
20885 /* avoid degenerate cases, so that (len - 1) won't underflow */
20886 duk__array_qsort(ctx, (duk_int_t) 0, (duk_int_t) (len - 1));
20887 }
20888
20889 DUK_ASSERT_TOP(ctx, 3);
20890 duk_pop(ctx);
20891 return 1; /* return ToObject(this) */
20892}
20893
20894/*
20895 * splice()
20896 */
20897
20898/* XXX: this compiles to over 500 bytes now, even without special handling
20899 * for an array part. Uses signed ints so does not handle full array range correctly.
20900 */
20901
20902/* XXX: can shift() / unshift() use the same helper?
20903 * shift() is (close to?) <--> splice(0, 1)
20904 * unshift is (close to?) <--> splice(0, 0, [items])?
20905 */
20906
20907DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
20908 duk_idx_t nargs;
20909 duk_uint32_t len;
20910 duk_bool_t have_delcount;
20911 duk_int_t item_count;
20912 duk_int_t act_start;
20913 duk_int_t del_count;
20914 duk_int_t i, n;
20915
20916 DUK_UNREF(have_delcount);
20917
20918 nargs = duk_get_top(ctx);
20919 if (nargs < 2) {
20920 duk_set_top(ctx, 2);
20921 nargs = 2;
20922 have_delcount = 0;
20923 } else {
20924 have_delcount = 1;
20925 }
20926
20927 /* XXX: len >= 0x80000000 won't work below because we need to be
20928 * able to represent -len.
20929 */
20930 len = duk__push_this_obj_len_u32_limited(ctx);
20931
20932 act_start = duk_to_int_clamped(ctx, 0, -((duk_int_t) len), (duk_int_t) len);
20933 if (act_start < 0) {
20934 act_start = len + act_start;
20935 }
20936 DUK_ASSERT(act_start >= 0 && act_start <= (duk_int_t) len);
20937
20938#ifdef DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT
20939 if (have_delcount) {
20940#endif
20941 del_count = duk_to_int_clamped(ctx, 1, 0, len - act_start);
20942#ifdef DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT
20943 } else {
20944 /* E5.1 standard behavior when deleteCount is not given would be
20945 * to treat it just like if 'undefined' was given, which coerces
20946 * ultimately to 0. Real world behavior is to splice to the end
20947 * of array, see test-bi-array-proto-splice-no-delcount.js.
20948 */
20949 del_count = len - act_start;
20950 }
20951#endif
20952
20953 DUK_ASSERT(nargs >= 2);
20954 item_count = (duk_int_t) (nargs - 2);
20955
20956 DUK_ASSERT(del_count >= 0 && del_count <= (duk_int_t) len - act_start);
20957 DUK_ASSERT(del_count + act_start <= (duk_int_t) len);
20958
20959 /* For now, restrict result array into 32-bit length range. */
20960 if (((duk_double_t) len) - ((duk_double_t) del_count) + ((duk_double_t) item_count) > (duk_double_t) DUK_UINT32_MAX) {
20961 DUK_D(DUK_DPRINT("Array.prototype.splice() would go beyond 32-bit length, throw"));
20962 return DUK_RET_RANGE_ERROR;
20963 }
20964
20965 duk_push_array(ctx);
20966
20967 /* stack[0] = start
20968 * stack[1] = deleteCount
20969 * stack[2...nargs-1] = items
20970 * stack[nargs] = ToObject(this) -3
20971 * stack[nargs+1] = ToUint32(length) -2
20972 * stack[nargs+2] = result array -1
20973 */
20974
20975 DUK_ASSERT_TOP(ctx, nargs + 3);
20976
20977 /* Step 9: copy elements-to-be-deleted into the result array */
20978
20979 for (i = 0; i < del_count; i++) {
20980 if (duk_get_prop_index(ctx, -3, (duk_uarridx_t) (act_start + i))) {
20981 duk_xdef_prop_index_wec(ctx, -2, i); /* throw flag irrelevant (false in std alg) */
20982 } else {
20983 duk_pop(ctx);
20984 }
20985 }
20986 duk_push_u32(ctx, (duk_uint32_t) del_count);
20987 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
20988
20989 /* Steps 12 and 13: reorganize elements to make room for itemCount elements */
20990
20991 if (item_count < del_count) {
20992 /* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 1
20993 * -> [ A B F G H ] (conceptual intermediate step)
20994 * -> [ A B . F G H ] (placeholder marked)
20995 * [ A B C F G H ] (actual result at this point, C will be replaced)
20996 */
20997
20998 DUK_ASSERT_TOP(ctx, nargs + 3);
20999
21000 n = len - del_count;
21001 for (i = act_start; i < n; i++) {
21002 if (duk_get_prop_index(ctx, -3, (duk_uarridx_t) (i + del_count))) {
21003 duk_put_prop_index(ctx, -4, (duk_uarridx_t) (i + item_count));
21004 } else {
21005 duk_pop(ctx);
21006 duk_del_prop_index(ctx, -3, (duk_uarridx_t) (i + item_count));
21007 }
21008 }
21009
21010 DUK_ASSERT_TOP(ctx, nargs + 3);
21011
21012 /* loop iterator init and limit changed from standard algorithm */
21013 n = len - del_count + item_count;
21014 for (i = len - 1; i >= n; i--) {
21015 duk_del_prop_index(ctx, -3, (duk_uarridx_t) i);
21016 }
21017
21018 DUK_ASSERT_TOP(ctx, nargs + 3);
21019 } else if (item_count > del_count) {
21020 /* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 4
21021 * -> [ A B F G H ] (conceptual intermediate step)
21022 * -> [ A B . . . . F G H ] (placeholder marked)
21023 * [ A B C D E F F G H ] (actual result at this point)
21024 */
21025
21026 DUK_ASSERT_TOP(ctx, nargs + 3);
21027
21028 /* loop iterator init and limit changed from standard algorithm */
21029 for (i = len - del_count - 1; i >= act_start; i--) {
21030 if (duk_get_prop_index(ctx, -3, (duk_uarridx_t) (i + del_count))) {
21031 duk_put_prop_index(ctx, -4, (duk_uarridx_t) (i + item_count));
21032 } else {
21033 duk_pop(ctx);
21034 duk_del_prop_index(ctx, -3, (duk_uarridx_t) (i + item_count));
21035 }
21036 }
21037
21038 DUK_ASSERT_TOP(ctx, nargs + 3);
21039 } else {
21040 /* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 3
21041 * -> [ A B F G H ] (conceptual intermediate step)
21042 * -> [ A B . . . F G H ] (placeholder marked)
21043 * [ A B C D E F G H ] (actual result at this point)
21044 */
21045 }
21046 DUK_ASSERT_TOP(ctx, nargs + 3);
21047
21048 /* Step 15: insert itemCount elements into the hole made above */
21049
21050 for (i = 0; i < item_count; i++) {
21051 duk_dup(ctx, i + 2); /* args start at index 2 */
21052 duk_put_prop_index(ctx, -4, (duk_uarridx_t) (act_start + i));
21053 }
21054
21055 /* Step 16: update length; note that the final length may be above 32 bit range
21056 * (but we checked above that this isn't the case here)
21057 */
21058
21059 duk_push_u32(ctx, len - del_count + item_count);
21060 duk_put_prop_stridx(ctx, -4, DUK_STRIDX_LENGTH);
21061
21062 /* result array is already at the top of stack */
21063 DUK_ASSERT_TOP(ctx, nargs + 3);
21064 return 1;
21065}
21066
21067/*
21068 * reverse()
21069 */
21070
21071DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reverse(duk_context *ctx) {
21072 duk_uint32_t len;
21073 duk_uint32_t middle;
21074 duk_uint32_t lower, upper;
21075 duk_bool_t have_lower, have_upper;
21076
21077 len = duk__push_this_obj_len_u32(ctx);
21078 middle = len / 2;
21079
21080 /* If len <= 1, middle will be 0 and for-loop bails out
21081 * immediately (0 < 0 -> false).
21082 */
21083
21084 for (lower = 0; lower < middle; lower++) {
21085 DUK_ASSERT(len >= 2);
21086 DUK_ASSERT_TOP(ctx, 2);
21087
21088 DUK_ASSERT(len >= lower + 1);
21089 upper = len - lower - 1;
21090
21091 have_lower = duk_get_prop_index(ctx, -2, (duk_uarridx_t) lower);
21092 have_upper = duk_get_prop_index(ctx, -3, (duk_uarridx_t) upper);
21093
21094 /* [ ToObject(this) ToUint32(length) lowerValue upperValue ] */
21095
21096 if (have_upper) {
21097 duk_put_prop_index(ctx, -4, (duk_uarridx_t) lower);
21098 } else {
21099 duk_del_prop_index(ctx, -4, (duk_uarridx_t) lower);
21100 duk_pop(ctx);
21101 }
21102
21103 if (have_lower) {
21104 duk_put_prop_index(ctx, -3, (duk_uarridx_t) upper);
21105 } else {
21106 duk_del_prop_index(ctx, -3, (duk_uarridx_t) upper);
21107 duk_pop(ctx);
21108 }
21109
21110 DUK_ASSERT_TOP(ctx, 2);
21111 }
21112
21113 DUK_ASSERT_TOP(ctx, 2);
21114 duk_pop(ctx); /* -> [ ToObject(this) ] */
21115 return 1;
21116}
21117
21118/*
21119 * slice()
21120 */
21121
21122DUK_INTERNAL duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx) {
21123 duk_uint32_t len;
21124 duk_int_t start, end;
21125 duk_int_t i;
21126 duk_uarridx_t idx;
21127 duk_uint32_t res_length = 0;
21128
21129 /* XXX: len >= 0x80000000 won't work below because we need to be
21130 * able to represent -len.
21131 */
21132 len = duk__push_this_obj_len_u32_limited(ctx);
21133 duk_push_array(ctx);
21134
21135 /* stack[0] = start
21136 * stack[1] = end
21137 * stack[2] = ToObject(this)
21138 * stack[3] = ToUint32(length)
21139 * stack[4] = result array
21140 */
21141
21142 start = duk_to_int_clamped(ctx, 0, -((duk_int_t) len), (duk_int_t) len);
21143 if (start < 0) {
21144 start = len + start;
21145 }
21146 /* XXX: could duk_is_undefined() provide defaulting undefined to 'len'
21147 * (the upper limit)?
21148 */
21149 if (duk_is_undefined(ctx, 1)) {
21150 end = len;
21151 } else {
21152 end = duk_to_int_clamped(ctx, 1, -((duk_int_t) len), (duk_int_t) len);
21153 if (end < 0) {
21154 end = len + end;
21155 }
21156 }
21157 DUK_ASSERT(start >= 0 && (duk_uint32_t) start <= len);
21158 DUK_ASSERT(end >= 0 && (duk_uint32_t) end <= len);
21159
21160 idx = 0;
21161 for (i = start; i < end; i++) {
21162 DUK_ASSERT_TOP(ctx, 5);
21163 if (duk_get_prop_index(ctx, 2, (duk_uarridx_t) i)) {
21164 duk_xdef_prop_index_wec(ctx, 4, idx);
21165 res_length = idx + 1;
21166 } else {
21167 duk_pop(ctx);
21168 }
21169 idx++;
21170 DUK_ASSERT_TOP(ctx, 5);
21171 }
21172
21173 duk_push_u32(ctx, res_length);
21174 duk_xdef_prop_stridx(ctx, 4, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
21175
21176 DUK_ASSERT_TOP(ctx, 5);
21177 return 1;
21178}
21179
21180/*
21181 * shift()
21182 */
21183
21184DUK_INTERNAL duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx) {
21185 duk_uint32_t len;
21186 duk_uint32_t i;
21187
21188 len = duk__push_this_obj_len_u32(ctx);
21189 if (len == 0) {
21190 duk_push_int(ctx, 0);
21191 duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH);
21192 return 0;
21193 }
21194
21195 duk_get_prop_index(ctx, 0, 0);
21196
21197 /* stack[0] = object (this)
21198 * stack[1] = ToUint32(length)
21199 * stack[2] = elem at index 0 (retval)
21200 */
21201
21202 for (i = 1; i < len; i++) {
21203 DUK_ASSERT_TOP(ctx, 3);
21204 if (duk_get_prop_index(ctx, 0, (duk_uarridx_t) i)) {
21205 /* fromPresent = true */
21206 duk_put_prop_index(ctx, 0, (duk_uarridx_t) (i - 1));
21207 } else {
21208 /* fromPresent = false */
21209 duk_del_prop_index(ctx, 0, (duk_uarridx_t) (i - 1));
21210 duk_pop(ctx);
21211 }
21212 }
21213 duk_del_prop_index(ctx, 0, (duk_uarridx_t) (len - 1));
21214
21215 duk_push_u32(ctx, (duk_uint32_t) (len - 1));
21216 duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH);
21217
21218 DUK_ASSERT_TOP(ctx, 3);
21219 return 1;
21220}
21221
21222/*
21223 * unshift()
21224 */
21225
21226DUK_INTERNAL duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx) {
21227 duk_idx_t nargs;
21228 duk_uint32_t len;
21229 duk_uint32_t i;
21230
21231 nargs = duk_get_top(ctx);
21232 len = duk__push_this_obj_len_u32(ctx);
21233
21234 /* stack[0...nargs-1] = unshift args (vararg)
21235 * stack[nargs] = ToObject(this)
21236 * stack[nargs+1] = ToUint32(length)
21237 */
21238
21239 DUK_ASSERT_TOP(ctx, nargs + 2);
21240
21241 /* Note: unshift() may operate on indices above unsigned 32-bit range
21242 * and the final length may be >= 2**32. However, we restrict the
21243 * final result to 32-bit range for practicality.
21244 */
21245
21246 if (len + (duk_uint32_t) nargs < len) {
21247 DUK_D(DUK_DPRINT("Array.prototype.unshift() would go beyond 32-bit length, throw"));
21248 return DUK_RET_RANGE_ERROR;
21249 }
21250
21251 i = len;
21252 while (i > 0) {
21253 DUK_ASSERT_TOP(ctx, nargs + 2);
21254 i--;
21255 /* k+argCount-1; note that may be above 32-bit range */
21256
21257 if (duk_get_prop_index(ctx, -2, (duk_uarridx_t) i)) {
21258 /* fromPresent = true */
21259 /* [ ... ToObject(this) ToUint32(length) val ] */
21260 duk_put_prop_index(ctx, -3, (duk_uarridx_t) (i + nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */
21261 } else {
21262 /* fromPresent = false */
21263 /* [ ... ToObject(this) ToUint32(length) val ] */
21264 duk_pop(ctx);
21265 duk_del_prop_index(ctx, -2, (duk_uarridx_t) (i + nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */
21266 }
21267 DUK_ASSERT_TOP(ctx, nargs + 2);
21268 }
21269
21270 for (i = 0; i < (duk_uint32_t) nargs; i++) {
21271 DUK_ASSERT_TOP(ctx, nargs + 2);
21272 duk_dup(ctx, i); /* -> [ ... ToObject(this) ToUint32(length) arg[i] ] */
21273 duk_put_prop_index(ctx, -3, (duk_uarridx_t) i);
21274 DUK_ASSERT_TOP(ctx, nargs + 2);
21275 }
21276
21277 DUK_ASSERT_TOP(ctx, nargs + 2);
21278 duk_push_u32(ctx, len + nargs);
21279 duk_dup_top(ctx); /* -> [ ... ToObject(this) ToUint32(length) final_len final_len ] */
21280 duk_put_prop_stridx(ctx, -4, DUK_STRIDX_LENGTH);
21281 return 1;
21282}
21283
21284/*
21285 * indexOf(), lastIndexOf()
21286 */
21287
21288DUK_INTERNAL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx) {
21289 duk_idx_t nargs;
21290 duk_int_t i, len;
21291 duk_int_t from_index;
21292 duk_small_int_t idx_step = duk_get_current_magic(ctx); /* idx_step is +1 for indexOf, -1 for lastIndexOf */
21293
21294 /* lastIndexOf() needs to be a vararg function because we must distinguish
21295 * between an undefined fromIndex and a "not given" fromIndex; indexOf() is
21296 * made vararg for symmetry although it doesn't strictly need to be.
21297 */
21298
21299 nargs = duk_get_top(ctx);
21300 duk_set_top(ctx, 2);
21301
21302 /* XXX: must be able to represent -len */
21303 len = (duk_int_t) duk__push_this_obj_len_u32_limited(ctx);
21304 if (len == 0) {
21305 goto not_found;
21306 }
21307
21308 /* Index clamping is a bit tricky, we must ensure that we'll only iterate
21309 * through elements that exist and that the specific requirements from E5.1
21310 * Sections 15.4.4.14 and 15.4.4.15 are fulfilled; especially:
21311 *
21312 * - indexOf: clamp to [-len,len], negative handling -> [0,len],
21313 * if clamped result is len, for-loop bails out immediately
21314 *
21315 * - lastIndexOf: clamp to [-len-1, len-1], negative handling -> [-1, len-1],
21316 * if clamped result is -1, for-loop bails out immediately
21317 *
21318 * If fromIndex is not given, ToInteger(undefined) = 0, which is correct
21319 * for indexOf() but incorrect for lastIndexOf(). Hence special handling,
21320 * and why lastIndexOf() needs to be a vararg function.
21321 */
21322
21323 if (nargs >= 2) {
21324 /* indexOf: clamp fromIndex to [-len, len]
21325 * (if fromIndex == len, for-loop terminates directly)
21326 *
21327 * lastIndexOf: clamp fromIndex to [-len - 1, len - 1]
21328 * (if clamped to -len-1 -> fromIndex becomes -1, terminates for-loop directly)
21329 */
21330 from_index = duk_to_int_clamped(ctx,
21331 1,
21332 (idx_step > 0 ? -len : -len - 1),
21333 (idx_step > 0 ? len : len - 1));
21334 if (from_index < 0) {
21335 /* for lastIndexOf, result may be -1 (mark immediate termination) */
21336 from_index = len + from_index;
21337 }
21338 } else {
21339 /* for indexOf, ToInteger(undefined) would be 0, i.e. correct, but
21340 * handle both indexOf and lastIndexOf specially here.
21341 */
21342 if (idx_step > 0) {
21343 from_index = 0;
21344 } else {
21345 from_index = len - 1;
21346 }
21347 }
21348
21349 /* stack[0] = searchElement
21350 * stack[1] = fromIndex
21351 * stack[2] = object
21352 * stack[3] = length (not needed, but not popped above)
21353 */
21354
21355 for (i = from_index; i >= 0 && i < len; i += idx_step) {
21356 DUK_ASSERT_TOP(ctx, 4);
21357
21358 if (duk_get_prop_index(ctx, 2, (duk_uarridx_t) i)) {
21359 DUK_ASSERT_TOP(ctx, 5);
21360 if (duk_strict_equals(ctx, 0, 4)) {
21361 duk_push_int(ctx, i);
21362 return 1;
21363 }
21364 }
21365
21366 duk_pop(ctx);
21367 }
21368
21369 not_found:
21370 duk_push_int(ctx, -1);
21371 return 1;
21372}
21373
21374/*
21375 * every(), some(), forEach(), map(), filter()
21376 */
21377
21378#define DUK__ITER_EVERY 0
21379#define DUK__ITER_SOME 1
21380#define DUK__ITER_FOREACH 2
21381#define DUK__ITER_MAP 3
21382#define DUK__ITER_FILTER 4
21383
21384/* XXX: This helper is a bit awkward because the handling for the different iteration
21385 * callers is quite different. This now compiles to a bit less than 500 bytes, so with
21386 * 5 callers the net result is about 100 bytes / caller.
21387 */
21388
21389DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) {
21390 duk_uint32_t len;
21391 duk_uint32_t i;
21392 duk_uarridx_t k;
21393 duk_bool_t bval;
21394 duk_small_int_t iter_type = duk_get_current_magic(ctx);
21395 duk_uint32_t res_length = 0;
21396
21397 /* each call this helper serves has nargs==2 */
21398 DUK_ASSERT_TOP(ctx, 2);
21399
21400 len = duk__push_this_obj_len_u32(ctx);
11fdf7f2 21401 duk_require_callable(ctx, 0);
7c673cae
FG
21402 /* if thisArg not supplied, behave as if undefined was supplied */
21403
21404 if (iter_type == DUK__ITER_MAP || iter_type == DUK__ITER_FILTER) {
21405 duk_push_array(ctx);
21406 } else {
21407 duk_push_undefined(ctx);
21408 }
21409
21410 /* stack[0] = callback
21411 * stack[1] = thisArg
21412 * stack[2] = object
21413 * stack[3] = ToUint32(length) (unused, but avoid unnecessary pop)
21414 * stack[4] = result array (or undefined)
21415 */
21416
21417 k = 0; /* result index for filter() */
21418 for (i = 0; i < len; i++) {
21419 DUK_ASSERT_TOP(ctx, 5);
21420
21421 if (!duk_get_prop_index(ctx, 2, (duk_uarridx_t) i)) {
21422#if defined(DUK_USE_NONSTD_ARRAY_MAP_TRAILER)
21423 /* Real world behavior for map(): trailing non-existent
21424 * elements don't invoke the user callback, but are still
21425 * counted towards result 'length'.
21426 */
21427 if (iter_type == DUK__ITER_MAP) {
21428 res_length = i + 1;
21429 }
21430#else
21431 /* Standard behavior for map(): trailing non-existent
21432 * elements don't invoke the user callback and are not
21433 * counted towards result 'length'.
21434 */
21435#endif
21436 duk_pop(ctx);
21437 continue;
21438 }
21439
21440 /* The original value needs to be preserved for filter(), hence
21441 * this funny order. We can't re-get the value because of side
21442 * effects.
21443 */
21444
21445 duk_dup(ctx, 0);
21446 duk_dup(ctx, 1);
21447 duk_dup(ctx, -3);
21448 duk_push_u32(ctx, i);
21449 duk_dup(ctx, 2); /* [ ... val callback thisArg val i obj ] */
21450 duk_call_method(ctx, 3); /* -> [ ... val retval ] */
21451
21452 switch (iter_type) {
21453 case DUK__ITER_EVERY:
21454 bval = duk_to_boolean(ctx, -1);
21455 if (!bval) {
21456 /* stack top contains 'false' */
21457 return 1;
21458 }
21459 break;
21460 case DUK__ITER_SOME:
21461 bval = duk_to_boolean(ctx, -1);
21462 if (bval) {
21463 /* stack top contains 'true' */
21464 return 1;
21465 }
21466 break;
21467 case DUK__ITER_FOREACH:
21468 /* nop */
21469 break;
21470 case DUK__ITER_MAP:
21471 duk_dup(ctx, -1);
21472 duk_xdef_prop_index_wec(ctx, 4, (duk_uarridx_t) i); /* retval to result[i] */
21473 res_length = i + 1;
21474 break;
21475 case DUK__ITER_FILTER:
21476 bval = duk_to_boolean(ctx, -1);
21477 if (bval) {
21478 duk_dup(ctx, -2); /* orig value */
21479 duk_xdef_prop_index_wec(ctx, 4, (duk_uarridx_t) k);
21480 k++;
21481 res_length = k;
21482 }
21483 break;
21484 default:
21485 DUK_UNREACHABLE();
21486 break;
21487 }
21488 duk_pop_2(ctx);
21489
21490 DUK_ASSERT_TOP(ctx, 5);
21491 }
21492
21493 switch (iter_type) {
21494 case DUK__ITER_EVERY:
21495 duk_push_true(ctx);
21496 break;
21497 case DUK__ITER_SOME:
21498 duk_push_false(ctx);
21499 break;
21500 case DUK__ITER_FOREACH:
21501 duk_push_undefined(ctx);
21502 break;
21503 case DUK__ITER_MAP:
21504 case DUK__ITER_FILTER:
21505 DUK_ASSERT_TOP(ctx, 5);
21506 DUK_ASSERT(duk_is_array(ctx, -1)); /* topmost element is the result array already */
21507 duk_push_u32(ctx, res_length);
21508 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
21509 break;
21510 default:
21511 DUK_UNREACHABLE();
21512 break;
21513 }
21514
21515 return 1;
7c673cae
FG
21516}
21517
21518/*
21519 * reduce(), reduceRight()
21520 */
21521
21522DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx) {
21523 duk_idx_t nargs;
21524 duk_bool_t have_acc;
21525 duk_uint32_t i, len;
21526 duk_small_int_t idx_step = duk_get_current_magic(ctx); /* idx_step is +1 for reduce, -1 for reduceRight */
21527
21528 /* We're a varargs function because we need to detect whether
21529 * initialValue was given or not.
21530 */
21531 nargs = duk_get_top(ctx);
21532 DUK_DDD(DUK_DDDPRINT("nargs=%ld", (long) nargs));
21533
21534 duk_set_top(ctx, 2);
21535 len = duk__push_this_obj_len_u32(ctx);
21536 if (!duk_is_callable(ctx, 0)) {
21537 goto type_error;
21538 }
21539
21540 /* stack[0] = callback fn
21541 * stack[1] = initialValue
21542 * stack[2] = object (coerced this)
21543 * stack[3] = length (not needed, but not popped above)
21544 * stack[4] = accumulator
21545 */
21546
21547 have_acc = 0;
21548 if (nargs >= 2) {
21549 duk_dup(ctx, 1);
21550 have_acc = 1;
21551 }
21552 DUK_DDD(DUK_DDDPRINT("have_acc=%ld, acc=%!T",
21553 (long) have_acc, (duk_tval *) duk_get_tval(ctx, 3)));
21554
21555 /* For len == 0, i is initialized to len - 1 which underflows.
21556 * The condition (i < len) will then exit the for-loop on the
21557 * first round which is correct. Similarly, loop termination
21558 * happens by i underflowing.
21559 */
21560
21561 for (i = (idx_step >= 0 ? 0 : len - 1);
21562 i < len; /* i >= 0 would always be true */
21563 i += idx_step) {
21564 DUK_DDD(DUK_DDDPRINT("i=%ld, len=%ld, have_acc=%ld, top=%ld, acc=%!T",
21565 (long) i, (long) len, (long) have_acc,
21566 (long) duk_get_top(ctx),
21567 (duk_tval *) duk_get_tval(ctx, 4)));
21568
21569 DUK_ASSERT((have_acc && duk_get_top(ctx) == 5) ||
21570 (!have_acc && duk_get_top(ctx) == 4));
21571
21572 if (!duk_has_prop_index(ctx, 2, (duk_uarridx_t) i)) {
21573 continue;
21574 }
21575
21576 if (!have_acc) {
21577 DUK_ASSERT_TOP(ctx, 4);
21578 duk_get_prop_index(ctx, 2, (duk_uarridx_t) i);
21579 have_acc = 1;
21580 DUK_ASSERT_TOP(ctx, 5);
21581 } else {
21582 DUK_ASSERT_TOP(ctx, 5);
21583 duk_dup(ctx, 0);
21584 duk_dup(ctx, 4);
21585 duk_get_prop_index(ctx, 2, (duk_uarridx_t) i);
21586 duk_push_u32(ctx, i);
21587 duk_dup(ctx, 2);
21588 DUK_DDD(DUK_DDDPRINT("calling reduce function: func=%!T, prev=%!T, curr=%!T, idx=%!T, obj=%!T",
21589 (duk_tval *) duk_get_tval(ctx, -5), (duk_tval *) duk_get_tval(ctx, -4),
21590 (duk_tval *) duk_get_tval(ctx, -3), (duk_tval *) duk_get_tval(ctx, -2),
21591 (duk_tval *) duk_get_tval(ctx, -1)));
21592 duk_call(ctx, 4);
21593 DUK_DDD(DUK_DDDPRINT("-> result: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
21594 duk_replace(ctx, 4);
21595 DUK_ASSERT_TOP(ctx, 5);
21596 }
21597 }
21598
21599 if (!have_acc) {
21600 goto type_error;
21601 }
21602
21603 DUK_ASSERT_TOP(ctx, 5);
21604 return 1;
21605
21606 type_error:
21607 return DUK_RET_TYPE_ERROR;
21608}
21609
21610#undef DUK__ARRAY_MID_JOIN_LIMIT
21611
21612#undef DUK__ITER_EVERY
21613#undef DUK__ITER_SOME
21614#undef DUK__ITER_FOREACH
21615#undef DUK__ITER_MAP
21616#undef DUK__ITER_FILTER
7c673cae
FG
21617/*
21618 * Boolean built-ins
21619 */
21620
21621/* include removed: duk_internal.h */
21622
21623/* Shared helper to provide toString() and valueOf(). Checks 'this', gets
21624 * the primitive value to stack top, and optionally coerces with ToString().
21625 */
21626DUK_INTERNAL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx) {
21627 duk_tval *tv;
21628 duk_hobject *h;
21629 duk_small_int_t coerce_tostring = duk_get_current_magic(ctx);
21630
21631 /* XXX: there is room to use a shared helper here, many built-ins
21632 * check the 'this' type, and if it's an object, check its class,
21633 * then get its internal value, etc.
21634 */
21635
21636 duk_push_this(ctx);
21637 tv = duk_get_tval(ctx, -1);
21638 DUK_ASSERT(tv != NULL);
21639
21640 if (DUK_TVAL_IS_BOOLEAN(tv)) {
21641 goto type_ok;
21642 } else if (DUK_TVAL_IS_OBJECT(tv)) {
21643 h = DUK_TVAL_GET_OBJECT(tv);
21644 DUK_ASSERT(h != NULL);
21645
21646 if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_BOOLEAN) {
21647 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
21648 DUK_ASSERT(duk_is_boolean(ctx, -1));
21649 goto type_ok;
21650 }
21651 }
21652
21653 return DUK_RET_TYPE_ERROR;
21654
21655 type_ok:
21656 if (coerce_tostring) {
21657 duk_to_string(ctx, -1);
21658 }
21659 return 1;
21660}
21661
21662DUK_INTERNAL duk_ret_t duk_bi_boolean_constructor(duk_context *ctx) {
21663 duk_hthread *thr = (duk_hthread *) ctx;
21664 duk_hobject *h_this;
21665
21666 DUK_UNREF(thr);
21667
21668 duk_to_boolean(ctx, 0);
21669
21670 if (duk_is_constructor_call(ctx)) {
21671 /* XXX: helper; rely on Boolean.prototype as being non-writable, non-configurable */
21672 duk_push_this(ctx);
21673 h_this = duk_get_hobject(ctx, -1);
21674 DUK_ASSERT(h_this != NULL);
21675 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_this) == thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE]);
21676
21677 DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_BOOLEAN);
21678
21679 duk_dup(ctx, 0); /* -> [ val obj val ] */
21680 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); /* XXX: proper flags? */
21681 } /* unbalanced stack */
21682
21683 return 1;
21684}
7c673cae
FG
21685/*
21686 * Duktape.Buffer, Node.js Buffer, and Khronos/ES6 TypedArray built-ins
21687 */
21688
21689/* include removed: duk_internal.h */
21690
21691/*
21692 * Misc helpers
21693 */
21694
21695#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
21696/* Map DUK_HBUFFEROBJECT_ELEM_xxx to duk_hobject class number.
21697 * Sync with duk_hbufferobject.h and duk_hobject.h.
21698 */
21699static const duk_uint8_t duk__buffer_class_from_elemtype[9] = {
21700 DUK_HOBJECT_CLASS_UINT8ARRAY,
21701 DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY,
21702 DUK_HOBJECT_CLASS_INT8ARRAY,
21703 DUK_HOBJECT_CLASS_UINT16ARRAY,
21704 DUK_HOBJECT_CLASS_INT16ARRAY,
21705 DUK_HOBJECT_CLASS_UINT32ARRAY,
21706 DUK_HOBJECT_CLASS_INT32ARRAY,
21707 DUK_HOBJECT_CLASS_FLOAT32ARRAY,
21708 DUK_HOBJECT_CLASS_FLOAT64ARRAY
21709};
21710#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
21711
21712#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
21713/* Map DUK_HBUFFEROBJECT_ELEM_xxx to prototype object built-in index.
21714 * Sync with duk_hbufferobject.h.
21715 */
21716static const duk_uint8_t duk__buffer_proto_from_elemtype[9] = {
21717 DUK_BIDX_UINT8ARRAY_PROTOTYPE,
21718 DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE,
21719 DUK_BIDX_INT8ARRAY_PROTOTYPE,
21720 DUK_BIDX_UINT16ARRAY_PROTOTYPE,
21721 DUK_BIDX_INT16ARRAY_PROTOTYPE,
21722 DUK_BIDX_UINT32ARRAY_PROTOTYPE,
21723 DUK_BIDX_INT32ARRAY_PROTOTYPE,
21724 DUK_BIDX_FLOAT32ARRAY_PROTOTYPE,
21725 DUK_BIDX_FLOAT64ARRAY_PROTOTYPE
21726};
21727#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
21728
21729#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
21730/* Map DUK__FLX_xxx to byte size.
21731 */
21732static const duk_uint8_t duk__buffer_nbytes_from_fldtype[6] = {
21733 1, /* DUK__FLD_8BIT */
21734 2, /* DUK__FLD_16BIT */
21735 4, /* DUK__FLD_32BIT */
21736 4, /* DUK__FLD_FLOAT */
21737 8, /* DUK__FLD_DOUBLE */
21738 0 /* DUK__FLD_VARINT; not relevant here */
21739};
21740#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
21741
21742#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
21743/* Bitfield for each DUK_HBUFFEROBJECT_ELEM_xxx indicating which element types
21744 * are compatible with a blind byte copy for the TypedArray set() method (also
21745 * used for TypedArray constructor). Array index is target buffer elem type,
21746 * bitfield indicates compatible source types. The types must have same byte
21747 * size and they must be coercion compatible.
21748 */
21749static duk_uint16_t duk__buffer_elemtype_copy_compatible[9] = {
21750 /* xxx -> DUK_HBUFFEROBJECT_ELEM_UINT8 */
21751 (1U << DUK_HBUFFEROBJECT_ELEM_UINT8) |
21752 (1U << DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED) |
21753 (1U << DUK_HBUFFEROBJECT_ELEM_INT8),
21754
21755 /* xxx -> DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED
21756 * Note: INT8 is -not- copy compatible, e.g. -1 would coerce to 0x00.
21757 */
21758 (1U << DUK_HBUFFEROBJECT_ELEM_UINT8) |
21759 (1U << DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED),
21760
21761 /* xxx -> DUK_HBUFFEROBJECT_ELEM_INT8 */
21762 (1U << DUK_HBUFFEROBJECT_ELEM_UINT8) |
21763 (1U << DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED) |
21764 (1U << DUK_HBUFFEROBJECT_ELEM_INT8),
21765
21766 /* xxx -> DUK_HBUFFEROBJECT_ELEM_UINT16 */
21767 (1U << DUK_HBUFFEROBJECT_ELEM_UINT16) |
21768 (1U << DUK_HBUFFEROBJECT_ELEM_INT16),
21769
21770 /* xxx -> DUK_HBUFFEROBJECT_ELEM_INT16 */
21771 (1U << DUK_HBUFFEROBJECT_ELEM_UINT16) |
21772 (1U << DUK_HBUFFEROBJECT_ELEM_INT16),
21773
21774 /* xxx -> DUK_HBUFFEROBJECT_ELEM_UINT32 */
21775 (1U << DUK_HBUFFEROBJECT_ELEM_UINT32) |
21776 (1U << DUK_HBUFFEROBJECT_ELEM_INT32),
21777
21778 /* xxx -> DUK_HBUFFEROBJECT_ELEM_INT32 */
21779 (1U << DUK_HBUFFEROBJECT_ELEM_UINT32) |
21780 (1U << DUK_HBUFFEROBJECT_ELEM_INT32),
21781
21782 /* xxx -> DUK_HBUFFEROBJECT_ELEM_FLOAT32 */
21783 (1U << DUK_HBUFFEROBJECT_ELEM_FLOAT32),
21784
21785 /* xxx -> DUK_HBUFFEROBJECT_ELEM_FLOAT64 */
21786 (1U << DUK_HBUFFEROBJECT_ELEM_FLOAT64)
21787};
21788#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
21789
21790#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
21791/* Shared helper. */
21792DUK_LOCAL duk_hbufferobject *duk__getrequire_bufobj_this(duk_context *ctx, duk_bool_t throw_flag) {
21793 duk_hthread *thr;
21794 duk_tval *tv;
21795 duk_hbufferobject *h_this;
21796
21797 DUK_ASSERT(ctx != NULL);
21798 thr = (duk_hthread *) ctx;
21799
21800 tv = duk_get_borrowed_this_tval(ctx);
21801 DUK_ASSERT(tv != NULL);
21802 if (DUK_TVAL_IS_OBJECT(tv)) {
21803 h_this = (duk_hbufferobject *) DUK_TVAL_GET_OBJECT(tv);
21804 DUK_ASSERT(h_this != NULL);
21805 if (DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) h_this)) {
21806 DUK_ASSERT_HBUFFEROBJECT_VALID(h_this);
21807 return h_this;
21808 }
21809 }
21810
21811 if (throw_flag) {
11fdf7f2 21812 DUK_ERROR_TYPE(thr, DUK_STR_NOT_BUFFER);
7c673cae
FG
21813 }
21814 return NULL;
21815}
21816#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
21817
21818#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
21819/* Check that 'this' is a duk_hbufferobject and return a pointer to it. */
21820DUK_LOCAL duk_hbufferobject *duk__get_bufobj_this(duk_context *ctx) {
21821 return duk__getrequire_bufobj_this(ctx, 0);
21822}
21823#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
21824
21825#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
21826/* Check that 'this' is a duk_hbufferobject and return a pointer to it
21827 * (NULL if not).
21828 */
21829DUK_LOCAL duk_hbufferobject *duk__require_bufobj_this(duk_context *ctx) {
21830 return duk__getrequire_bufobj_this(ctx, 1);
21831}
21832#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
21833
21834#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
21835/* Check that value is a duk_hbufferobject and return a pointer to it. */
21836DUK_LOCAL duk_hbufferobject *duk__require_bufobj_value(duk_context *ctx, duk_idx_t index) {
21837 duk_hthread *thr;
21838 duk_tval *tv;
21839 duk_hbufferobject *h_obj;
21840
21841 thr = (duk_hthread *) ctx;
21842
21843 /* Don't accept relative indices now. */
21844 DUK_ASSERT(index >= 0);
21845
21846 tv = duk_require_tval(ctx, index);
21847 DUK_ASSERT(tv != NULL);
21848 if (DUK_TVAL_IS_OBJECT(tv)) {
21849 h_obj = (duk_hbufferobject *) DUK_TVAL_GET_OBJECT(tv);
21850 DUK_ASSERT(h_obj != NULL);
21851 if (DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) h_obj)) {
21852 DUK_ASSERT_HBUFFEROBJECT_VALID(h_obj);
21853 return h_obj;
21854 }
21855 }
21856
11fdf7f2 21857 DUK_ERROR_TYPE(thr, DUK_STR_NOT_BUFFER);
7c673cae
FG
21858 return NULL; /* not reachable */
21859}
21860#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
21861
21862DUK_LOCAL void duk__set_bufobj_buffer(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_hbuffer *h_val) {
21863 duk_hthread *thr;
21864
21865 thr = (duk_hthread *) ctx;
21866 DUK_UNREF(thr);
21867
21868 DUK_ASSERT(ctx != NULL);
21869 DUK_ASSERT(h_bufobj != NULL);
21870 DUK_ASSERT(h_bufobj->buf == NULL); /* no need to decref */
21871 DUK_ASSERT(h_val != NULL);
21872 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
21873
21874 h_bufobj->buf = h_val;
21875 DUK_HBUFFER_INCREF(thr, h_val);
21876 h_bufobj->length = (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_val);
21877 DUK_ASSERT(h_bufobj->shift == 0);
21878 DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8);
21879
21880 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
21881}
21882
21883#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
21884DUK_LOCAL duk_hbufferobject *duk__push_arraybuffer_with_length(duk_context *ctx, duk_uint_t len) {
21885 duk_hbuffer *h_val;
21886 duk_hbufferobject *h_bufobj;
21887
21888 (void) duk_push_fixed_buffer(ctx, (duk_size_t) len);
21889 h_val = (duk_hbuffer *) duk_get_hbuffer(ctx, -1);
21890 DUK_ASSERT(h_val != NULL);
21891
21892 h_bufobj = duk_push_bufferobject_raw(ctx,
21893 DUK_HOBJECT_FLAG_EXTENSIBLE |
21894 DUK_HOBJECT_FLAG_BUFFEROBJECT |
21895 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
21896 DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
21897 DUK_ASSERT(h_bufobj != NULL);
21898
21899 duk__set_bufobj_buffer(ctx, h_bufobj, h_val);
21900 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
21901
21902 return h_bufobj;
21903}
21904#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
21905
21906#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
21907/* Shared offset/length coercion helper. */
21908DUK_LOCAL void duk__resolve_offset_opt_length(duk_context *ctx,
21909 duk_hbufferobject *h_bufarg,
21910 duk_idx_t idx_offset,
21911 duk_idx_t idx_length,
21912 duk_uint_t *out_offset,
21913 duk_uint_t *out_length,
21914 duk_bool_t throw_flag) {
21915 duk_hthread *thr;
21916 duk_int_t offset_signed;
21917 duk_int_t length_signed;
21918 duk_uint_t offset;
21919 duk_uint_t length;
21920
21921 thr = (duk_hthread *) ctx;
21922 DUK_UNREF(thr);
21923
21924 offset_signed = duk_to_int(ctx, idx_offset);
21925 if (offset_signed < 0) {
21926 goto fail_range;
21927 }
21928 offset = (duk_uint_t) offset_signed;
21929 if (offset > h_bufarg->length) {
21930 goto fail_range;
21931 }
21932 DUK_ASSERT_DISABLE(offset >= 0); /* unsigned */
21933 DUK_ASSERT(offset <= h_bufarg->length);
21934
21935 if (duk_is_undefined(ctx, idx_length)) {
21936 DUK_ASSERT(h_bufarg->length >= offset);
21937 length = h_bufarg->length - offset; /* >= 0 */
21938 } else {
21939 length_signed = duk_to_int(ctx, idx_length);
21940 if (length_signed < 0) {
21941 goto fail_range;
21942 }
21943 length = (duk_uint_t) length_signed;
21944 DUK_ASSERT(h_bufarg->length >= offset);
21945 if (length > h_bufarg->length - offset) {
21946 /* Unlike for negative arguments, some call sites
21947 * want length to be clamped if it's positive.
21948 */
21949 if (throw_flag) {
21950 goto fail_range;
21951 } else {
21952 length = h_bufarg->length - offset;
21953 }
21954 }
21955 }
21956 DUK_ASSERT_DISABLE(length >= 0); /* unsigned */
21957 DUK_ASSERT(offset + length <= h_bufarg->length);
21958
21959 *out_offset = offset;
21960 *out_length = length;
21961 return;
21962
21963 fail_range:
11fdf7f2 21964 DUK_ERROR_RANGE(thr, DUK_STR_INVALID_CALL_ARGS);
7c673cae
FG
21965}
21966#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
21967
21968#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
21969/* Shared lenient buffer length clamping helper. No negative indices, no
21970 * element/byte shifting.
21971 */
21972DUK_LOCAL void duk__clamp_startend_nonegidx_noshift(duk_context *ctx,
21973 duk_hbufferobject *h_bufobj,
21974 duk_idx_t idx_start,
21975 duk_idx_t idx_end,
21976 duk_int_t *out_start_offset,
21977 duk_int_t *out_end_offset) {
21978 duk_int_t buffer_length;
21979 duk_int_t start_offset;
21980 duk_int_t end_offset;
21981
21982 DUK_ASSERT(out_start_offset != NULL);
21983 DUK_ASSERT(out_end_offset != NULL);
21984
21985 buffer_length = (duk_int_t) h_bufobj->length;
21986
21987 /* undefined coerces to zero which is correct */
21988 start_offset = duk_to_int_clamped(ctx, idx_start, 0, buffer_length);
21989 if (duk_is_undefined(ctx, idx_end)) {
21990 end_offset = buffer_length;
21991 } else {
21992 end_offset = duk_to_int_clamped(ctx, idx_end, start_offset, buffer_length);
21993 }
21994
21995 DUK_ASSERT(start_offset >= 0);
21996 DUK_ASSERT(start_offset <= buffer_length);
21997 DUK_ASSERT(end_offset >= 0);
21998 DUK_ASSERT(end_offset <= buffer_length);
21999 DUK_ASSERT(start_offset <= end_offset);
22000
22001 *out_start_offset = start_offset;
22002 *out_end_offset = end_offset;
22003}
22004#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
22005
22006#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
22007/* Shared lenient buffer length clamping helper. Indices are treated as
22008 * element indices (though output values are byte offsets) which only
22009 * really matters for TypedArray views as other buffer object have a zero
22010 * shift. Negative indices are counted from end of input slice; crossed
22011 * indices are clamped to zero length; and final indices are clamped
22012 * against input slice. Used for e.g. ArrayBuffer slice().
22013 */
22014DUK_LOCAL void duk__clamp_startend_negidx_shifted(duk_context *ctx,
22015 duk_hbufferobject *h_bufobj,
22016 duk_idx_t idx_start,
22017 duk_idx_t idx_end,
22018 duk_int_t *out_start_offset,
22019 duk_int_t *out_end_offset) {
22020 duk_int_t buffer_length;
22021 duk_int_t start_offset;
22022 duk_int_t end_offset;
22023
22024 DUK_ASSERT(out_start_offset != NULL);
22025 DUK_ASSERT(out_end_offset != NULL);
22026
22027 buffer_length = (duk_int_t) h_bufobj->length;
22028 buffer_length >>= h_bufobj->shift; /* as elements */
22029
22030 /* Resolve start/end offset as element indices first; arguments
22031 * at idx_start/idx_end are element offsets. Working with element
22032 * indices first also avoids potential for wrapping.
22033 */
22034
22035 start_offset = duk_to_int(ctx, idx_start);
22036 if (start_offset < 0) {
22037 start_offset = buffer_length + start_offset;
22038 }
22039 if (duk_is_undefined(ctx, idx_end)) {
22040 end_offset = buffer_length;
22041 } else {
22042 end_offset = duk_to_int(ctx, idx_end);
22043 if (end_offset < 0) {
22044 end_offset = buffer_length + end_offset;
22045 }
22046 }
22047 /* Note: start_offset/end_offset can still be < 0 here. */
22048
22049 if (start_offset < 0) {
22050 start_offset = 0;
22051 } else if (start_offset > buffer_length) {
22052 start_offset = buffer_length;
22053 }
22054 if (end_offset < start_offset) {
22055 end_offset = start_offset;
22056 } else if (end_offset > buffer_length) {
22057 end_offset = buffer_length;
22058 }
22059 DUK_ASSERT(start_offset >= 0);
22060 DUK_ASSERT(start_offset <= buffer_length);
22061 DUK_ASSERT(end_offset >= 0);
22062 DUK_ASSERT(end_offset <= buffer_length);
22063 DUK_ASSERT(start_offset <= end_offset);
22064
22065 /* Convert indices to byte offsets. */
22066 start_offset <<= h_bufobj->shift;
22067 end_offset <<= h_bufobj->shift;
22068
22069 *out_start_offset = start_offset;
22070 *out_end_offset = end_offset;
22071}
22072#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
22073
22074/*
22075 * Indexed read/write helpers (also used from outside this file)
22076 */
22077
22078DUK_INTERNAL void duk_hbufferobject_push_validated_read(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) {
22079 duk_double_union du;
22080
11fdf7f2 22081 DUK_MEMCPY((void *) du.uc, (const void *) p, (size_t) elem_size);
7c673cae
FG
22082
22083 switch (h_bufobj->elem_type) {
22084 case DUK_HBUFFEROBJECT_ELEM_UINT8:
22085#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
22086 case DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED:
22087#endif
22088 duk_push_uint(ctx, (duk_uint_t) du.uc[0]);
22089 break;
22090#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
22091 /* These are not needed when only Duktape.Buffer is supported. */
22092 case DUK_HBUFFEROBJECT_ELEM_INT8:
22093 duk_push_int(ctx, (duk_int_t) (duk_int8_t) du.uc[0]);
22094 break;
22095 case DUK_HBUFFEROBJECT_ELEM_UINT16:
22096 duk_push_uint(ctx, (duk_uint_t) du.us[0]);
22097 break;
22098 case DUK_HBUFFEROBJECT_ELEM_INT16:
22099 duk_push_int(ctx, (duk_int_t) (duk_int16_t) du.us[0]);
22100 break;
22101 case DUK_HBUFFEROBJECT_ELEM_UINT32:
22102 duk_push_uint(ctx, (duk_uint_t) du.ui[0]);
22103 break;
22104 case DUK_HBUFFEROBJECT_ELEM_INT32:
22105 duk_push_int(ctx, (duk_int_t) (duk_int32_t) du.ui[0]);
22106 break;
22107 case DUK_HBUFFEROBJECT_ELEM_FLOAT32:
22108 duk_push_number(ctx, (duk_double_t) du.f[0]);
22109 break;
22110 case DUK_HBUFFEROBJECT_ELEM_FLOAT64:
22111 duk_push_number(ctx, (duk_double_t) du.d);
22112 break;
22113#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
22114 default:
22115 DUK_UNREACHABLE();
22116 }
22117}
22118
22119DUK_INTERNAL void duk_hbufferobject_validated_write(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) {
22120 duk_double_union du;
22121
22122 /* NOTE! Caller must ensure that any side effects from the
22123 * coercions below are safe. If that cannot be guaranteed
22124 * (which is normally the case), caller must coerce the
22125 * argument using duk_to_number() before any pointer
22126 * validations; the result of duk_to_number() always coerces
22127 * without side effects here.
22128 */
22129
22130 switch (h_bufobj->elem_type) {
22131 case DUK_HBUFFEROBJECT_ELEM_UINT8:
22132 du.uc[0] = (duk_uint8_t) duk_to_uint32(ctx, -1);
22133 break;
22134#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
22135 /* These are not needed when only Duktape.Buffer is supported. */
22136 case DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED:
22137 du.uc[0] = (duk_uint8_t) duk_to_uint8clamped(ctx, -1);
22138 break;
22139 case DUK_HBUFFEROBJECT_ELEM_INT8:
22140 du.uc[0] = (duk_uint8_t) duk_to_int32(ctx, -1);
22141 break;
22142 case DUK_HBUFFEROBJECT_ELEM_UINT16:
22143 du.us[0] = (duk_uint16_t) duk_to_uint32(ctx, -1);
22144 break;
22145 case DUK_HBUFFEROBJECT_ELEM_INT16:
22146 du.us[0] = (duk_uint16_t) duk_to_int32(ctx, -1);
22147 break;
22148 case DUK_HBUFFEROBJECT_ELEM_UINT32:
22149 du.ui[0] = (duk_uint32_t) duk_to_uint32(ctx, -1);
22150 break;
22151 case DUK_HBUFFEROBJECT_ELEM_INT32:
22152 du.ui[0] = (duk_uint32_t) duk_to_int32(ctx, -1);
22153 break;
22154 case DUK_HBUFFEROBJECT_ELEM_FLOAT32:
22155 du.f[0] = (duk_float_t) duk_to_number(ctx, -1);
22156 break;
22157 case DUK_HBUFFEROBJECT_ELEM_FLOAT64:
22158 du.d = (duk_double_t) duk_to_number(ctx, -1);
22159 break;
22160#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
22161 default:
22162 DUK_UNREACHABLE();
22163 }
22164
11fdf7f2 22165 DUK_MEMCPY((void *) p, (const void *) du.uc, (size_t) elem_size);
7c673cae
FG
22166}
22167
22168/*
22169 * Duktape.Buffer: constructor
22170 */
22171
22172DUK_INTERNAL duk_ret_t duk_bi_buffer_constructor(duk_context *ctx) {
22173 duk_hthread *thr;
22174 duk_size_t buf_size;
22175 duk_small_int_t buf_dynamic;
22176 duk_uint8_t *buf_data;
22177 const duk_uint8_t *src_data;
22178
22179 thr = (duk_hthread *) ctx;
22180 DUK_UNREF(thr);
22181
22182 /*
22183 * Constructor arguments are currently somewhat compatible with
22184 * (keep it that way if possible):
22185 *
22186 * http://nodejs.org/api/buffer.html
22187 *
22188 * Note that the ToBuffer() coercion (duk_to_buffer()) does NOT match
22189 * the constructor behavior.
22190 */
22191
22192 buf_dynamic = duk_get_boolean(ctx, 1); /* default to false */
22193
22194 switch (duk_get_type(ctx, 0)) {
22195 case DUK_TYPE_NUMBER: {
22196 /* new buffer of specified size */
22197 buf_size = (duk_size_t) duk_to_int(ctx, 0);
22198 (void) duk_push_buffer(ctx, buf_size, buf_dynamic);
22199 break;
22200 }
22201 case DUK_TYPE_BUFFER: {
22202 /* return input buffer, converted to a Duktape.Buffer object
22203 * if called as a constructor (no change if called as a
22204 * function).
22205 */
22206 duk_set_top(ctx, 1);
22207 break;
22208 }
22209 case DUK_TYPE_STRING: {
22210 /* new buffer with string contents */
22211 src_data = (const duk_uint8_t *) duk_get_lstring(ctx, 0, &buf_size);
22212 DUK_ASSERT(src_data != NULL); /* even for zero-length string */
22213 buf_data = (duk_uint8_t *) duk_push_buffer(ctx, buf_size, buf_dynamic);
22214 DUK_MEMCPY((void *) buf_data, (const void *) src_data, (size_t) buf_size);
22215 break;
22216 }
22217 case DUK_TYPE_OBJECT: {
22218 /* For all duk_hbufferobjects, get the plain buffer inside
22219 * without making a copy. This is compatible with Duktape 1.2
22220 * but means that a slice/view information is ignored and the
22221 * full underlying buffer is returned.
22222 *
22223 * If called as a constructor, a new Duktape.Buffer object
22224 * pointing to the same plain buffer is created below.
22225 */
22226 duk_hbufferobject *h_bufobj;
22227 h_bufobj = (duk_hbufferobject *) duk_get_hobject(ctx, 0);
22228 DUK_ASSERT(h_bufobj != NULL);
22229 if (!DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) h_bufobj)) {
22230 return DUK_RET_TYPE_ERROR;
22231 }
22232 if (h_bufobj->buf == NULL) {
22233 return DUK_RET_TYPE_ERROR;
22234 }
22235 duk_push_hbuffer(ctx, h_bufobj->buf);
22236 break;
22237 }
22238 case DUK_TYPE_NONE:
22239 default: {
22240 return DUK_RET_TYPE_ERROR;
22241 }
22242 }
22243 DUK_ASSERT(duk_is_buffer(ctx, -1));
22244
22245 /* stack is unbalanced, but: [ <something> buf ] */
22246
22247 if (duk_is_constructor_call(ctx)) {
22248 duk_hbufferobject *h_bufobj;
22249 duk_hbuffer *h_val;
22250
22251 h_val = duk_get_hbuffer(ctx, -1);
22252 DUK_ASSERT(h_val != NULL);
22253
22254 h_bufobj = duk_push_bufferobject_raw(ctx,
22255 DUK_HOBJECT_FLAG_EXTENSIBLE |
22256 DUK_HOBJECT_FLAG_BUFFEROBJECT |
22257 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER),
22258 DUK_BIDX_BUFFER_PROTOTYPE);
22259 DUK_ASSERT(h_bufobj != NULL);
22260
22261 duk__set_bufobj_buffer(ctx, h_bufobj, h_val);
22262
22263 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
22264 }
22265 /* Note: unbalanced stack on purpose */
22266
22267 return 1;
22268}
22269
22270/*
22271 * Node.js Buffer: constructor
22272 */
22273
22274#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
22275DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx) {
22276 /* Internal class is Object: Object.prototype.toString.call(new Buffer(0))
22277 * prints "[object Object]".
22278 */
22279 duk_int_t len;
22280 duk_int_t i;
7c673cae
FG
22281 duk_hbuffer *h_buf;
22282 duk_hbufferobject *h_bufobj;
22283 duk_size_t buf_size;
22284
22285 switch (duk_get_type(ctx, 0)) {
22286 case DUK_TYPE_BUFFER: {
22287 /* Custom behavior: plain buffer is used as internal buffer
22288 * without making a copy (matches Duktape.Buffer).
22289 */
22290 duk_set_top(ctx, 1); /* -> [ buffer ] */
22291 break;
22292 }
22293 case DUK_TYPE_NUMBER: {
22294 len = duk_to_int_clamped(ctx, 0, 0, DUK_INT_MAX);
11fdf7f2 22295 (void) duk_push_fixed_buffer(ctx, (duk_size_t) len);
7c673cae
FG
22296 break;
22297 }
22298 case DUK_TYPE_OBJECT: {
11fdf7f2
TL
22299 duk_uint8_t *buf;
22300
7c673cae
FG
22301 (void) duk_get_prop_string(ctx, 0, "length");
22302 len = duk_to_int_clamped(ctx, -1, 0, DUK_INT_MAX);
22303 duk_pop(ctx);
22304 buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len);
22305 for (i = 0; i < len; i++) {
22306 /* XXX: fast path for array arguments? */
22307 duk_get_prop_index(ctx, 0, (duk_uarridx_t) i);
22308 buf[i] = (duk_uint8_t) (duk_to_uint32(ctx, -1) & 0xffU);
22309 duk_pop(ctx);
22310 }
22311 break;
22312 }
22313 case DUK_TYPE_STRING: {
22314 /* ignore encoding for now */
22315 duk_dup(ctx, 0);
11fdf7f2 22316 (void) duk_to_buffer(ctx, -1, &buf_size);
7c673cae
FG
22317 break;
22318 }
22319 default:
22320 return DUK_RET_TYPE_ERROR;
22321 }
22322
22323 DUK_ASSERT(duk_is_buffer(ctx, -1));
22324 h_buf = duk_get_hbuffer(ctx, -1);
22325 DUK_ASSERT(h_buf != NULL);
22326
22327 h_bufobj = duk_push_bufferobject_raw(ctx,
22328 DUK_HOBJECT_FLAG_EXTENSIBLE |
22329 DUK_HOBJECT_FLAG_BUFFEROBJECT |
22330 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER),
22331 DUK_BIDX_NODEJS_BUFFER_PROTOTYPE);
22332 DUK_ASSERT(h_bufobj != NULL);
22333
22334 h_bufobj->buf = h_buf;
22335 DUK_HBUFFER_INCREF(thr, h_buf);
22336 DUK_ASSERT(h_bufobj->offset == 0);
22337 h_bufobj->length = (duk_int_t) DUK_HBUFFER_GET_SIZE(h_buf);
22338 DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8);
22339
22340 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
22341
22342 return 1;
22343}
22344#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
22345DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx) {
22346 DUK_UNREF(ctx);
22347 return DUK_RET_UNSUPPORTED_ERROR;
22348}
22349#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
22350
22351/*
22352 * ArrayBuffer, DataView, and TypedArray constructors
22353 */
22354
22355#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
22356DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx) {
11fdf7f2 22357 duk_hthread *thr;
7c673cae
FG
22358 duk_hbufferobject *h_bufobj;
22359 duk_hbuffer *h_val;
22360
11fdf7f2
TL
22361 DUK_ASSERT_CTX_VALID(ctx);
22362 thr = (duk_hthread *) ctx;
22363 DUK_UNREF(thr);
22364
7c673cae
FG
22365 /* XXX: function flag to make this automatic? */
22366 if (!duk_is_constructor_call(ctx)) {
22367 return DUK_RET_TYPE_ERROR;
22368 }
22369
22370 if (duk_is_buffer(ctx, 0)) {
22371 /* Custom behavior: plain buffer is used as internal buffer
22372 * without making a copy (matches Duktape.Buffer).
22373 */
22374
22375 h_val = duk_get_hbuffer(ctx, 0);
22376 DUK_ASSERT(h_val != NULL);
22377
22378 /* XXX: accept any duk_hbufferobject type as an input also? */
22379 } else {
22380 duk_int_t len;
22381 len = duk_to_int(ctx, 0);
22382 if (len < 0) {
22383 goto fail_length;
22384 }
22385 (void) duk_push_fixed_buffer(ctx, (duk_size_t) len);
22386 h_val = (duk_hbuffer *) duk_get_hbuffer(ctx, -1);
22387 DUK_ASSERT(h_val != NULL);
11fdf7f2
TL
22388
22389#if !defined(DUK_USE_ZERO_BUFFER_DATA)
22390 /* Khronos/ES6 requires zeroing even when DUK_USE_ZERO_BUFFER_DATA
22391 * is not set.
22392 */
22393 DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) h_val));
22394 DUK_MEMZERO((void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_val), (duk_size_t) len);
22395#endif
7c673cae
FG
22396 }
22397
22398 h_bufobj = duk_push_bufferobject_raw(ctx,
22399 DUK_HOBJECT_FLAG_EXTENSIBLE |
22400 DUK_HOBJECT_FLAG_BUFFEROBJECT |
22401 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
22402 DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
22403 DUK_ASSERT(h_bufobj != NULL);
22404
22405 duk__set_bufobj_buffer(ctx, h_bufobj, h_val);
22406 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
22407
22408 return 1;
22409
22410 fail_length:
22411 return DUK_RET_RANGE_ERROR;
22412}
22413#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
22414DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx) {
22415 DUK_UNREF(ctx);
22416 return DUK_RET_UNSUPPORTED_ERROR;
22417}
22418#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
22419
22420
22421/* Format of magic, bits:
22422 * 0...1: elem size shift (0-3)
22423 * 2...5: elem type (DUK_HBUFFEROBJECT_ELEM_xxx)
22424 */
22425
22426#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
22427DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
22428 duk_hthread *thr;
22429 duk_tval *tv;
22430 duk_hobject *h_obj;
22431 duk_hbufferobject *h_bufobj = NULL;
22432 duk_hbufferobject *h_bufarr = NULL;
22433 duk_hbufferobject *h_bufarg = NULL;
22434 duk_hbuffer *h_val;
22435 duk_small_uint_t magic;
22436 duk_small_uint_t shift;
22437 duk_small_uint_t elem_type;
22438 duk_small_uint_t elem_size;
22439 duk_small_uint_t class_num;
22440 duk_small_uint_t proto_bidx;
22441 duk_uint_t align_mask;
22442 duk_uint_t elem_length;
22443 duk_int_t elem_length_signed;
22444 duk_uint_t byte_length;
22445 duk_small_uint_t copy_mode;
22446
22447 thr = (duk_hthread *) ctx;
22448 DUK_UNREF(thr);
22449
22450 /* XXX: function flag to make this automatic? */
22451 if (!duk_is_constructor_call(ctx)) {
22452 return DUK_RET_TYPE_ERROR;
22453 }
22454
22455 /* We could fit built-in index into magic but that'd make the magic
22456 * number dependent on built-in numbering (genbuiltins.py doesn't
22457 * handle that yet). So map both class and prototype from the
22458 * element type.
22459 */
22460 magic = duk_get_current_magic(ctx);
22461 shift = magic & 0x03; /* bits 0...1: shift */
22462 elem_type = (magic >> 2) & 0x0f; /* bits 2...5: type */
22463 elem_size = 1 << shift;
22464 align_mask = elem_size - 1;
22465 DUK_ASSERT(elem_type < sizeof(duk__buffer_proto_from_elemtype) / sizeof(duk_uint8_t));
22466 proto_bidx = duk__buffer_proto_from_elemtype[elem_type];
22467 DUK_ASSERT(proto_bidx < DUK_NUM_BUILTINS);
22468 DUK_ASSERT(elem_type < sizeof(duk__buffer_class_from_elemtype) / sizeof(duk_uint8_t));
22469 class_num = duk__buffer_class_from_elemtype[elem_type];
22470
22471 DUK_DD(DUK_DDPRINT("typedarray constructor, magic=%d, shift=%d, elem_type=%d, "
22472 "elem_size=%d, proto_bidx=%d, class_num=%d",
22473 (int) magic, (int) shift, (int) elem_type, (int) elem_size,
22474 (int) proto_bidx, (int) class_num));
22475
22476 /* Argument variants. When the argument is an ArrayBuffer a view to
22477 * the same buffer is created; otherwise a new ArrayBuffer is always
22478 * created.
22479 */
22480
22481 tv = duk_get_tval(ctx, 0);
22482 DUK_ASSERT(tv != NULL); /* arg count */
22483 if (DUK_TVAL_IS_OBJECT(tv)) {
22484 h_obj = DUK_TVAL_GET_OBJECT(tv);
22485 DUK_ASSERT(h_obj != NULL);
22486
22487 if (DUK_HOBJECT_GET_CLASS_NUMBER(h_obj) == DUK_HOBJECT_CLASS_ARRAYBUFFER) {
22488 /* ArrayBuffer: unlike any other argument variant, create
22489 * a view into the existing buffer.
22490 */
22491
22492 duk_int_t byte_offset_signed;
22493 duk_uint_t byte_offset;
22494
22495 h_bufarg = (duk_hbufferobject *) h_obj;
22496
22497 byte_offset_signed = duk_to_int(ctx, 1);
22498 if (byte_offset_signed < 0) {
22499 goto fail_arguments;
22500 }
22501 byte_offset = (duk_uint_t) byte_offset_signed;
22502 if (byte_offset > h_bufarg->length ||
22503 (byte_offset & align_mask) != 0) {
22504 /* Must be >= 0 and multiple of element size. */
22505 goto fail_arguments;
22506 }
22507 if (duk_is_undefined(ctx, 2)) {
22508 DUK_ASSERT(h_bufarg->length >= byte_offset);
22509 byte_length = h_bufarg->length - byte_offset;
22510 if ((byte_length & align_mask) != 0) {
22511 /* Must be element size multiple from
22512 * start offset to end of buffer.
22513 */
22514 goto fail_arguments;
22515 }
22516 elem_length = (byte_length >> shift);
22517 } else {
22518 elem_length_signed = duk_to_int(ctx, 2);
22519 if (elem_length_signed < 0) {
22520 goto fail_arguments;
22521 }
22522 elem_length = (duk_uint_t) elem_length_signed;
22523 byte_length = elem_length << shift;
22524 if ((byte_length >> shift) != elem_length) {
22525 /* Byte length would overflow. */
22526 /* XXX: easier check with less code? */
22527 goto fail_arguments;
22528 }
22529 DUK_ASSERT(h_bufarg->length >= byte_offset);
22530 if (byte_length > h_bufarg->length - byte_offset) {
22531 /* Not enough data. */
22532 goto fail_arguments;
22533 }
22534 }
11fdf7f2 22535 DUK_UNREF(elem_length);
7c673cae
FG
22536 DUK_ASSERT_DISABLE(byte_offset >= 0);
22537 DUK_ASSERT(byte_offset <= h_bufarg->length);
22538 DUK_ASSERT_DISABLE(byte_length >= 0);
22539 DUK_ASSERT(byte_offset + byte_length <= h_bufarg->length);
22540 DUK_ASSERT((elem_length << shift) == byte_length);
22541
22542 h_bufobj = duk_push_bufferobject_raw(ctx,
22543 DUK_HOBJECT_FLAG_EXTENSIBLE |
22544 DUK_HOBJECT_FLAG_BUFFEROBJECT |
22545 DUK_HOBJECT_CLASS_AS_FLAGS(class_num),
22546 proto_bidx);
22547 h_val = h_bufarg->buf;
22548 if (h_val == NULL) {
22549 return DUK_RET_TYPE_ERROR;
22550 }
22551 h_bufobj->buf = h_val;
22552 DUK_HBUFFER_INCREF(thr, h_val);
22553 h_bufobj->offset = h_bufarg->offset + byte_offset;
22554 h_bufobj->length = byte_length;
11fdf7f2
TL
22555 h_bufobj->shift = (duk_uint8_t) shift;
22556 h_bufobj->elem_type = (duk_uint8_t) elem_type;
7c673cae
FG
22557 h_bufobj->is_view = 1;
22558 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
22559
22560 /* Set .buffer to the argument ArrayBuffer. */
22561 duk_dup(ctx, 0);
22562 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE);
22563 duk_compact(ctx, -1);
22564 return 1;
22565 } else if (DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) {
22566 /* TypedArray (or other non-ArrayBuffer duk_hbufferobject).
22567 * Conceptually same behavior as for an Array-like argument,
22568 * with a few fast paths.
22569 */
22570
22571 h_bufarg = (duk_hbufferobject *) h_obj;
22572 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufarg);
22573 elem_length_signed = (duk_int_t) (h_bufarg->length >> h_bufarg->shift);
22574 if (h_bufarg->buf == NULL) {
22575 return DUK_RET_TYPE_ERROR;
22576 }
22577
22578 /* Select copy mode. Must take into account element
22579 * compatibility and validity of the underlying source
22580 * buffer.
22581 */
22582
22583 DUK_DDD(DUK_DDDPRINT("selecting copy mode for bufobj arg, "
22584 "src byte_length=%ld, src shift=%d, "
22585 "src/dst elem_length=%ld; "
22586 "dst shift=%d -> dst byte_length=%ld",
22587 (long) h_bufarg->length, (int) h_bufarg->shift,
22588 (long) elem_length_signed, (int) shift,
22589 (long) (elem_length_signed << shift)));
22590
22591 copy_mode = 2; /* default is explicit index read/write copy */
22592 DUK_ASSERT(elem_type < sizeof(duk__buffer_elemtype_copy_compatible) / sizeof(duk_uint16_t));
22593 if (DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg)) {
22594 if ((duk__buffer_elemtype_copy_compatible[elem_type] & (1 << h_bufarg->elem_type)) != 0) {
22595 DUK_DDD(DUK_DDDPRINT("source/target are copy compatible, memcpy"));
22596 DUK_ASSERT(shift == h_bufarg->shift); /* byte sizes will match */
22597 copy_mode = 0;
22598 } else {
22599 DUK_DDD(DUK_DDDPRINT("source/target not copy compatible but valid, fast copy"));
22600 copy_mode = 1;
22601 }
22602 }
22603 } else {
22604 /* Array or Array-like */
22605 elem_length_signed = (duk_int_t) duk_get_length(ctx, 0);
22606 copy_mode = 2;
22607 }
11fdf7f2
TL
22608 } else if (DUK_TVAL_IS_BUFFER(tv)) {
22609 /* Accept plain buffer values like array initializers
22610 * (new in Duktape 1.4.0).
22611 */
22612 duk_hbuffer *h_srcbuf;
22613 h_srcbuf = DUK_TVAL_GET_BUFFER(tv);
22614 elem_length_signed = (duk_int_t) DUK_HBUFFER_GET_SIZE(h_srcbuf);
22615 copy_mode = 2; /* XXX: could add fast path for u8 compatible views */
7c673cae
FG
22616 } else {
22617 /* Non-object argument is simply int coerced, matches
22618 * V8 behavior (except for "null", which we coerce to
22619 * 0 but V8 TypeErrors).
22620 */
22621 elem_length_signed = duk_to_int(ctx, 0);
22622 copy_mode = 3;
22623 }
22624 if (elem_length_signed < 0) {
22625 goto fail_arguments;
22626 }
22627 elem_length = (duk_uint_t) elem_length_signed;
22628 byte_length = (duk_uint_t) (elem_length << shift);
22629 if ((byte_length >> shift) != elem_length) {
22630 /* Byte length would overflow. */
22631 /* XXX: easier check with less code? */
22632 goto fail_arguments;
22633 }
22634
22635 DUK_DDD(DUK_DDDPRINT("elem_length=%ld, byte_length=%ld",
22636 (long) elem_length, (long) byte_length));
22637
22638 /* ArrayBuffer argument is handled specially above; the rest of the
22639 * argument variants are handled by shared code below.
22640 */
22641
22642 /* Push a new ArrayBuffer (becomes view .buffer) */
22643 h_bufarr = duk__push_arraybuffer_with_length(ctx, byte_length);
22644 DUK_ASSERT(h_bufarr != NULL);
22645 h_val = h_bufarr->buf;
22646 DUK_ASSERT(h_val != NULL);
22647
22648 /* Push the resulting view object and attach the ArrayBuffer. */
22649 h_bufobj = duk_push_bufferobject_raw(ctx,
22650 DUK_HOBJECT_FLAG_EXTENSIBLE |
22651 DUK_HOBJECT_FLAG_BUFFEROBJECT |
22652 DUK_HOBJECT_CLASS_AS_FLAGS(class_num),
22653 proto_bidx);
22654
22655 h_bufobj->buf = h_val;
22656 DUK_HBUFFER_INCREF(thr, h_val);
22657 DUK_ASSERT(h_bufobj->offset == 0);
22658 h_bufobj->length = byte_length;
11fdf7f2
TL
22659 h_bufobj->shift = (duk_uint8_t) shift;
22660 h_bufobj->elem_type = (duk_uint8_t) elem_type;
7c673cae
FG
22661 h_bufobj->is_view = 1;
22662 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
22663
22664 /* Set .buffer */
22665 duk_dup(ctx, -2);
22666 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE);
22667 duk_compact(ctx, -1);
22668
22669 /* Copy values, the copy method depends on the arguments.
22670 *
22671 * Copy mode decision may depend on the validity of the underlying
22672 * buffer of the source argument; there must be no harmful side effects
22673 * from there to here for copy_mode to still be valid.
22674 */
22675 DUK_DDD(DUK_DDDPRINT("copy mode: %d", (int) copy_mode));
22676 switch (copy_mode) {
22677 case 0: {
22678 /* Use byte copy. */
22679
22680 duk_uint8_t *p_src;
22681 duk_uint8_t *p_dst;
22682
22683 DUK_ASSERT(h_bufobj != NULL);
22684 DUK_ASSERT(h_bufobj->buf != NULL);
22685 DUK_ASSERT(DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj));
22686 DUK_ASSERT(h_bufarg != NULL);
22687 DUK_ASSERT(h_bufarg->buf != NULL);
22688 DUK_ASSERT(DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg));
22689
22690 p_dst = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufobj);
22691 p_src = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufarg);
22692
22693 DUK_DDD(DUK_DDDPRINT("using memcpy: p_src=%p, p_dst=%p, byte_length=%ld",
22694 (void *) p_src, (void *) p_dst, (long) byte_length));
22695
22696 DUK_MEMCPY((void *) p_dst, (const void *) p_src, (size_t) byte_length);
22697 break;
22698 }
22699 case 1: {
22700 /* Copy values through direct validated reads and writes. */
22701
22702 duk_small_uint_t src_elem_size;
22703 duk_small_uint_t dst_elem_size;
22704 duk_uint8_t *p_src;
22705 duk_uint8_t *p_src_end;
22706 duk_uint8_t *p_dst;
22707
22708 DUK_ASSERT(h_bufobj != NULL);
22709 DUK_ASSERT(h_bufobj->buf != NULL);
22710 DUK_ASSERT(DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj));
22711 DUK_ASSERT(h_bufarg != NULL);
22712 DUK_ASSERT(h_bufarg->buf != NULL);
22713 DUK_ASSERT(DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg));
22714
22715 src_elem_size = 1 << h_bufarg->shift;
22716 dst_elem_size = elem_size;
22717
22718 p_src = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufarg);
22719 p_dst = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufobj);
22720 p_src_end = p_src + h_bufarg->length;
22721
22722 DUK_DDD(DUK_DDDPRINT("using fast copy: p_src=%p, p_src_end=%p, p_dst=%p, "
22723 "src_elem_size=%d, dst_elem_size=%d",
22724 (void *) p_src, (void *) p_src_end, (void *) p_dst,
22725 (int) src_elem_size, (int) dst_elem_size));
22726
22727 while (p_src != p_src_end) {
22728 DUK_DDD(DUK_DDDPRINT("fast path per element copy loop: "
22729 "p_src=%p, p_src_end=%p, p_dst=%p",
22730 (void *) p_src, (void *) p_src_end, (void *) p_dst));
22731 /* A validated read() is always a number, so it's write coercion
22732 * is always side effect free an won't invalidate pointers etc.
22733 */
22734 duk_hbufferobject_push_validated_read(ctx, h_bufarg, p_src, src_elem_size);
22735 duk_hbufferobject_validated_write(ctx, h_bufobj, p_dst, dst_elem_size);
22736 duk_pop(ctx);
22737 p_src += src_elem_size;
22738 p_dst += dst_elem_size;
22739 }
22740 break;
22741 }
22742 case 2: {
22743 /* Copy values by index reads and writes. Let virtual
22744 * property handling take care of coercion.
22745 */
22746 duk_uint_t i;
22747
22748 DUK_DDD(DUK_DDDPRINT("using slow copy"));
22749
22750 for (i = 0; i < elem_length; i++) {
22751 duk_get_prop_index(ctx, 0, (duk_uarridx_t) i);
22752 duk_put_prop_index(ctx, -2, (duk_uarridx_t) i);
22753 }
22754 break;
22755 }
22756 default:
22757 case 3: {
22758 /* No copy, leave zero bytes in the buffer. There's no
22759 * ambiguity with Float32/Float64 because zero bytes also
22760 * represent 0.0.
22761 */
11fdf7f2
TL
22762#if !defined(DUK_USE_ZERO_BUFFER_DATA)
22763 /* Khronos/ES6 requires zeroing even when DUK_USE_ZERO_BUFFER_DATA
22764 * is not set.
22765 */
22766 DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) h_val));
22767 DUK_MEMZERO((void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_val), (duk_size_t) byte_length);
22768#endif
7c673cae
FG
22769
22770 DUK_DDD(DUK_DDDPRINT("using no copy"));
22771 break;
22772 }
22773 }
22774
22775 return 1;
22776
22777 fail_arguments:
22778 return DUK_RET_RANGE_ERROR;
22779}
22780#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
22781DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
22782 DUK_UNREF(ctx);
22783 return DUK_RET_UNSUPPORTED_ERROR;
22784}
22785#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
22786
22787#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
22788DUK_INTERNAL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx) {
22789 duk_hbufferobject *h_bufarg;
22790 duk_hbufferobject *h_bufobj;
22791 duk_hbuffer *h_val;
22792 duk_uint_t offset;
22793 duk_uint_t length;
22794
22795 /* XXX: function flag to make this automatic? */
22796 if (!duk_is_constructor_call(ctx)) {
22797 return DUK_RET_TYPE_ERROR;
22798 }
22799
22800 h_bufarg = duk__require_bufobj_value(ctx, 0);
22801 DUK_ASSERT(h_bufarg != NULL);
22802
22803 duk__resolve_offset_opt_length(ctx, h_bufarg, 1, 2, &offset, &length, 1 /*throw_flag*/);
22804 DUK_ASSERT(offset <= h_bufarg->length);
22805 DUK_ASSERT(offset + length <= h_bufarg->length);
22806
22807 h_bufobj = duk_push_bufferobject_raw(ctx,
22808 DUK_HOBJECT_FLAG_EXTENSIBLE |
22809 DUK_HOBJECT_FLAG_BUFFEROBJECT |
22810 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATAVIEW),
22811 DUK_BIDX_DATAVIEW_PROTOTYPE);
22812
22813 h_val = h_bufarg->buf;
22814 if (h_val == NULL) {
22815 return DUK_RET_TYPE_ERROR;
22816 }
22817 h_bufobj->buf = h_val;
22818 DUK_HBUFFER_INCREF(thr, h_val);
22819 h_bufobj->offset = h_bufarg->offset + offset;
22820 h_bufobj->length = length;
22821 DUK_ASSERT(h_bufobj->shift == 0);
22822 DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8);
22823 h_bufobj->is_view = 1;
22824
22825 /* The DataView .buffer property is ordinarily set to the argument
22826 * which is an ArrayBuffer. We accept any duk_hbufferobject as
22827 * an argument and .buffer will be set to the argument regardless
22828 * of what it is. This may be a bit confusing if the argument
22829 * is e.g. a DataView or another TypedArray view.
22830 *
22831 * XXX: Copy .buffer property from a DataView/TypedArray argument?
22832 * Create a fresh ArrayBuffer for Duktape.Buffer and Node.js Buffer
22833 * arguments? See: test-bug-dataview-buffer-prop.js.
22834 */
22835
22836 duk_dup(ctx, 0);
22837 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE);
22838 duk_compact(ctx, -1);
22839
22840 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
22841 return 1;
22842}
22843#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
22844DUK_INTERNAL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx) {
22845 DUK_UNREF(ctx);
22846 return DUK_RET_UNSUPPORTED_ERROR;
22847}
22848#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
22849
22850/*
22851 * ArrayBuffer.isView()
22852 */
22853
22854#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
22855DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx) {
22856 duk_hobject *h_obj;
22857 duk_bool_t ret = 0;
22858
22859 h_obj = duk_get_hobject(ctx, 0);
22860 if (h_obj != NULL && DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) {
22861 ret = ((duk_hbufferobject *) h_obj)->is_view;
22862 }
22863 duk_push_boolean(ctx, ret);
22864 return 1;
22865}
22866#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
22867DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx) {
22868 DUK_UNREF(ctx);
22869 return DUK_RET_UNSUPPORTED_ERROR;
22870}
22871#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
22872
22873/*
22874 * Node.js Buffer: toString([encoding], [start], [end])
22875 */
22876
22877#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
22878DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx) {
22879 duk_hthread *thr;
22880 duk_hbufferobject *h_this;
22881 duk_int_t start_offset, end_offset;
22882 duk_uint8_t *buf_slice;
22883 duk_size_t slice_length;
22884
22885 thr = (duk_hthread *) ctx;
22886 DUK_UNREF(thr);
22887
22888 h_this = duk__get_bufobj_this(ctx);
22889 if (h_this == NULL) {
22890 /* XXX: happens e.g. when evaluating: String(Buffer.prototype). */
22891 duk_push_string(ctx, "[object Object]");
22892 return 1;
22893 }
22894 DUK_ASSERT_HBUFFEROBJECT_VALID(h_this);
22895
22896 /* ignore encoding for now */
22897
22898 duk__clamp_startend_nonegidx_noshift(ctx, h_this, 1 /*idx_start*/, 2 /*idx_end*/, &start_offset, &end_offset);
22899
22900 slice_length = (duk_size_t) (end_offset - start_offset);
22901 buf_slice = (duk_uint8_t *) duk_push_fixed_buffer(ctx, slice_length);
22902 DUK_ASSERT(buf_slice != NULL);
22903
22904 if (h_this->buf == NULL) {
22905 goto type_error;
22906 }
22907
22908 if (DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_this, start_offset + slice_length)) {
22909 DUK_MEMCPY((void *) buf_slice,
22910 (const void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
11fdf7f2 22911 (size_t) slice_length);
7c673cae
FG
22912 } else {
22913 /* not covered, return all zeroes */
22914 ;
22915 }
22916
22917 duk_to_string(ctx, -1);
22918 return 1;
22919
22920 type_error:
22921 return DUK_RET_TYPE_ERROR;
22922}
22923#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
22924DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx) {
22925 DUK_UNREF(ctx);
22926 return DUK_RET_UNSUPPORTED_ERROR;
22927}
22928#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
22929
22930/*
22931 * Duktape.Buffer: toString(), valueOf()
22932 */
22933
22934#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
22935DUK_INTERNAL duk_ret_t duk_bi_buffer_prototype_tostring_shared(duk_context *ctx) {
22936 duk_hthread *thr;
22937 duk_tval *tv;
22938 duk_small_int_t to_string = duk_get_current_magic(ctx);
22939
22940 thr = (duk_hthread *) ctx;
22941 DUK_UNREF(thr);
22942
22943 tv = duk_get_borrowed_this_tval(ctx);
22944 DUK_ASSERT(tv != NULL);
22945
22946 if (DUK_TVAL_IS_BUFFER(tv)) {
22947 duk_hbuffer *h_buf;
22948 h_buf = DUK_TVAL_GET_BUFFER(tv);
22949 DUK_ASSERT(h_buf != NULL);
22950 duk_push_hbuffer(ctx, h_buf);
22951 } else if (DUK_TVAL_IS_OBJECT(tv)) {
22952 duk_hobject *h;
22953 duk_hbufferobject *h_bufobj;
22954
22955 /* Accept any duk_hbufferobject, though we're only normally
22956 * called for Duktape.Buffer values.
22957 */
22958 h = DUK_TVAL_GET_OBJECT(tv);
22959 DUK_ASSERT(h != NULL);
22960 if (!DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
22961 DUK_DD(DUK_DDPRINT("toString/valueOf() called for a non-bufferobject object"));
22962 goto type_error;
22963 }
22964 h_bufobj = (duk_hbufferobject *) h;
22965 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
22966
22967 if (h_bufobj->buf == NULL) {
22968 DUK_DD(DUK_DDPRINT("toString/valueOf() called for a bufferobject with NULL buf"));
22969 goto type_error;
22970 }
22971 duk_push_hbuffer(ctx, h_bufobj->buf);
22972 } else {
22973 goto type_error;
22974 }
22975
22976 if (to_string) {
22977 duk_to_string(ctx, -1);
22978 }
22979 return 1;
22980
22981 type_error:
22982 return DUK_RET_TYPE_ERROR;
22983}
22984#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
22985DUK_INTERNAL duk_ret_t duk_bi_buffer_prototype_tostring_shared(duk_context *ctx) {
22986 DUK_UNREF(ctx);
22987 return DUK_RET_UNSUPPORTED_ERROR;
22988}
22989#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
22990
22991/*
22992 * Node.js Buffer.prototype: toJSON()
22993 */
22994
22995#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
22996DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx) {
22997 duk_hthread *thr;
22998 duk_hbufferobject *h_this;
22999 duk_uint8_t *buf;
23000 duk_uint_t i;
23001
23002 thr = (duk_hthread *) ctx;
23003 DUK_UNREF(thr);
23004 h_this = duk__require_bufobj_this(ctx);
23005 DUK_ASSERT(h_this != NULL);
23006
23007 if (h_this->buf == NULL || !DUK_HBUFFEROBJECT_VALID_SLICE(h_this)) {
23008 /* Serialize uncovered backing buffer as a null; doesn't
23009 * really matter as long we're memory safe.
23010 */
23011 duk_push_null(ctx);
23012 return 1;
23013 }
23014
23015 duk_push_object(ctx);
23016 duk_push_hstring_stridx(ctx, DUK_STRIDX_UC_BUFFER);
23017 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_TYPE);
23018
23019 duk_push_array(ctx);
23020 for (i = 0; i < h_this->length; i++) {
23021 /* XXX: regetting the pointer may be overkill - we're writing
23022 * to a side-effect free array here.
23023 */
23024 DUK_ASSERT(h_this->buf != NULL);
23025 buf = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this);
23026 duk_push_uint(ctx, (duk_uint_t) buf[i]);
23027 duk_put_prop_index(ctx, -2, (duk_idx_t) i);
23028 }
23029 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_DATA);
23030
23031 return 1;
23032}
23033#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
23034DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx) {
23035 DUK_UNREF(ctx);
23036 return DUK_RET_UNSUPPORTED_ERROR;
23037}
23038#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
23039
23040/*
23041 * Node.js Buffer.prototype.equals()
23042 * Node.js Buffer.prototype.compare()
23043 * Node.js Buffer.compare()
23044 */
23045
23046#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
23047DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx) {
23048 duk_hthread *thr;
23049 duk_small_uint_t magic;
23050 duk_hbufferobject *h_bufarg1;
23051 duk_hbufferobject *h_bufarg2;
23052 duk_small_int_t comp_res;
23053
23054 thr = (duk_hthread *) ctx;
23055 DUK_UNREF(thr);
23056
23057 magic = duk_get_current_magic(ctx);
23058 if (magic & 0x02) {
23059 /* Static call style. */
23060 h_bufarg1 = duk__require_bufobj_value(ctx, 0);
23061 h_bufarg2 = duk__require_bufobj_value(ctx, 1);
23062 } else {
23063 h_bufarg1 = duk__require_bufobj_this(ctx);
23064 h_bufarg2 = duk__require_bufobj_value(ctx, 0);
23065 }
23066 DUK_ASSERT(h_bufarg1 != NULL);
23067 DUK_ASSERT(h_bufarg2 != NULL);
23068
23069 /* We want to compare the slice/view areas of the arguments.
23070 * If either slice/view is invalid (underlying buffer is shorter)
23071 * ensure equals() is false, but otherwise the only thing that
23072 * matters is to be memory safe.
23073 */
23074
23075 if (DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg1) &&
23076 DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg2)) {
23077 comp_res = duk_js_data_compare((const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufarg1->buf) + h_bufarg1->offset,
23078 (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufarg2->buf) + h_bufarg2->offset,
23079 (duk_size_t) h_bufarg1->length,
23080 (duk_size_t) h_bufarg2->length);
23081 } else {
23082 comp_res = -1; /* either nonzero value is ok */
23083 }
23084
23085 if (magic & 0x01) {
23086 /* compare: similar to string comparison but for buffer data. */
23087 duk_push_int(ctx, comp_res);
23088 } else {
23089 /* equals */
23090 duk_push_boolean(ctx, (comp_res == 0));
23091 }
23092
23093 return 1;
23094}
23095#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
23096DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx) {
23097 DUK_UNREF(ctx);
23098 return DUK_RET_UNSUPPORTED_ERROR;
23099}
23100#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
23101
23102/*
23103 * Node.js Buffer.prototype.fill()
23104 */
23105
23106#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
23107DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) {
23108 duk_hthread *thr;
23109 duk_hbufferobject *h_this;
23110 const duk_uint8_t *fill_str_ptr;
23111 duk_size_t fill_str_len;
23112 duk_uint8_t fill_value;
23113 duk_int_t fill_offset;
23114 duk_int_t fill_end;
23115 duk_size_t fill_length;
23116 duk_uint8_t *p;
23117
23118 thr = (duk_hthread *) ctx;
23119 DUK_UNREF(thr);
23120
23121 h_this = duk__require_bufobj_this(ctx);
23122 DUK_ASSERT(h_this != NULL);
23123 if (h_this->buf == NULL) {
23124 return DUK_RET_TYPE_ERROR;
23125 }
23126
23127 /* [ value offset end ] */
23128
23129 if (duk_is_string(ctx, 0)) {
23130 fill_str_ptr = (const duk_uint8_t *) duk_get_lstring(ctx, 0, &fill_str_len);
23131 DUK_ASSERT(fill_str_ptr != NULL);
23132 } else {
23133 fill_value = (duk_uint8_t) duk_to_uint32(ctx, 0);
23134 fill_str_ptr = (const duk_uint8_t *) &fill_value;
23135 fill_str_len = 1;
23136 }
23137
23138 /* Fill offset handling is more lenient than in Node.js. */
23139
23140 duk__clamp_startend_nonegidx_noshift(ctx, h_this, 1 /*idx_start*/, 2 /*idx_end*/, &fill_offset, &fill_end);
23141
23142 DUK_DDD(DUK_DDDPRINT("fill: fill_value=%02x, fill_offset=%ld, fill_end=%ld, view length=%ld",
23143 (unsigned int) fill_value, (long) fill_offset, (long) fill_end, (long) h_this->length));
23144
23145 DUK_ASSERT(fill_end - fill_offset >= 0);
23146 DUK_ASSERT(h_this->buf != NULL);
23147
23148 p = (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + fill_offset);
23149 fill_length = (duk_size_t) (fill_end - fill_offset);
23150 if (fill_str_len == 1) {
23151 /* Handle single character fills as memset() even when
23152 * the fill data comes from a one-char argument.
23153 */
23154 DUK_MEMSET((void *) p, (int) fill_str_ptr[0], (size_t) fill_length);
23155 } else if (fill_str_len > 1) {
23156 duk_size_t i, n, t;
23157
23158 for (i = 0, n = (fill_end - fill_offset), t = 0; i < n; i++) {
23159 p[i] = fill_str_ptr[t++];
23160 if (t >= fill_str_len) {
23161 t = 0;
23162 }
23163 }
23164 } else {
23165 DUK_DDD(DUK_DDDPRINT("zero size fill pattern, ignore silently"));
23166 }
23167
23168 /* Return the Buffer to allow chaining: b.fill(0x11).fill(0x22, 3, 5).toString() */
23169 duk_push_this(ctx);
23170 return 1;
23171}
23172#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
23173DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) {
23174 DUK_UNREF(ctx);
23175 return DUK_RET_UNSUPPORTED_ERROR;
23176}
23177#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
23178
23179/*
23180 * Node.js Buffer.prototype.write(string, [offset], [length], [encoding])
23181 */
23182
23183#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
23184DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx) {
23185 duk_hthread *thr;
23186 duk_hbufferobject *h_this;
23187 duk_uint_t offset;
23188 duk_uint_t length;
23189 const duk_uint8_t *str_data;
23190 duk_size_t str_len;
23191
23192 thr = (duk_hthread *) ctx;
23193 DUK_UNREF(thr);
23194
23195 h_this = duk__require_bufobj_this(ctx);
23196 DUK_ASSERT(h_this != NULL);
23197
23198 /* Argument must be a string, e.g. a buffer is not allowed. */
23199 str_data = (const duk_uint8_t *) duk_require_lstring(ctx, 0, &str_len);
23200
23201 duk__resolve_offset_opt_length(ctx, h_this, 1, 2, &offset, &length, 0 /*throw_flag*/);
23202 DUK_ASSERT(offset <= h_this->length);
23203 DUK_ASSERT(offset + length <= h_this->length);
23204
23205 /* XXX: encoding is ignored now. */
23206
23207 if (length > str_len) {
23208 length = (duk_uint_t) str_len;
23209 }
23210
23211 if (DUK_HBUFFEROBJECT_VALID_SLICE(h_this)) {
23212 /* Cannot overlap. */
23213 DUK_MEMCPY((void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + offset),
23214 (const void *) str_data,
23215 (size_t) length);
23216 } else {
23217 DUK_DDD(DUK_DDDPRINT("write() target buffer is not covered, silent ignore"));
23218 }
23219
23220 duk_push_uint(ctx, length);
23221 return 1;
23222}
23223#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
23224DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx) {
23225 DUK_UNREF(ctx);
23226 return DUK_RET_UNSUPPORTED_ERROR;
23227}
23228#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
23229
23230/*
23231 * Node.js Buffer.prototype.copy()
23232 */
23233
23234#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
23235DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) {
23236 duk_hthread *thr;
23237 duk_hbufferobject *h_this;
23238 duk_hbufferobject *h_bufarg;
23239 duk_int_t source_length;
23240 duk_int_t target_length;
23241 duk_int_t target_start, source_start, source_end;
23242 duk_uint_t target_ustart, source_ustart, source_uend;
23243 duk_uint_t copy_size = 0;
23244
23245 /* [ targetBuffer targetStart sourceStart sourceEnd ] */
23246
23247 thr = (duk_hthread *) ctx;
23248 DUK_UNREF(thr);
23249
23250 h_this = duk__require_bufobj_this(ctx);
23251 h_bufarg = duk__require_bufobj_value(ctx, 0);
23252 DUK_ASSERT(h_this != NULL);
23253 DUK_ASSERT(h_bufarg != NULL);
23254 source_length = (duk_int_t) h_this->length;
23255 target_length = (duk_int_t) h_bufarg->length;
23256
23257 target_start = duk_to_int(ctx, 1);
23258 source_start = duk_to_int(ctx, 2);
23259 if (duk_is_undefined(ctx, 3)) {
23260 source_end = source_length;
23261 } else {
23262 source_end = duk_to_int(ctx, 3);
23263 }
23264
23265 DUK_DDD(DUK_DDDPRINT("checking copy args: target_start=%ld, target_length=%ld, "
23266 "source_start=%ld, source_end=%ld, source_length=%ld",
23267 (long) target_start, (long) h_bufarg->length,
23268 (long) source_start, (long) source_end, (long) source_length));
23269
23270 /* This behavior mostly mimics Node.js now. */
23271
23272 if (source_start < 0 || source_end < 0 || target_start < 0) {
23273 /* Negative offsets cause a RangeError. */
23274 goto fail_bounds;
23275 }
23276 source_ustart = (duk_uint_t) source_start;
23277 source_uend = (duk_uint_t) source_end;
23278 target_ustart = (duk_uint_t) target_start;
23279 if (source_ustart >= source_uend || /* crossed offsets or zero size */
23280 source_ustart >= (duk_uint_t) source_length || /* source out-of-bounds (but positive) */
23281 target_ustart >= (duk_uint_t) target_length) { /* target out-of-bounds (but positive) */
23282 goto silent_ignore;
23283 }
23284 if (source_uend >= (duk_uint_t) source_length) {
23285 /* Source end clamped silently to available length. */
23286 source_uend = source_length;
23287 }
23288 copy_size = source_uend - source_ustart;
23289 if (target_ustart + copy_size > (duk_uint_t) target_length) {
23290 /* Clamp to target's end if too long.
23291 *
23292 * NOTE: there's no overflow possibility in the comparison;
23293 * both target_ustart and copy_size are >= 0 and based on
23294 * values in duk_int_t range. Adding them as duk_uint_t
23295 * values is then guaranteed not to overflow.
23296 */
23297 DUK_ASSERT(target_ustart + copy_size >= target_ustart); /* no overflow */
23298 DUK_ASSERT(target_ustart + copy_size >= copy_size); /* no overflow */
23299 copy_size = (duk_uint_t) target_length - target_ustart;
23300 }
23301
23302 DUK_DDD(DUK_DDDPRINT("making copy: target_ustart=%lu source_ustart=%lu copy_size=%lu",
23303 (unsigned long) target_ustart, (unsigned long) source_ustart,
23304 (unsigned long) copy_size));
23305
23306 DUK_ASSERT(copy_size >= 1);
23307 DUK_ASSERT(source_ustart <= (duk_uint_t) source_length);
23308 DUK_ASSERT(source_ustart + copy_size <= (duk_uint_t) source_length);
23309 DUK_ASSERT(target_ustart <= (duk_uint_t) target_length);
23310 DUK_ASSERT(target_ustart + copy_size <= (duk_uint_t) target_length);
23311
23312 /* Ensure copy is covered by underlying buffers. */
23313 DUK_ASSERT(h_bufarg->buf != NULL); /* length check */
23314 DUK_ASSERT(h_this->buf != NULL); /* length check */
23315 if (DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_bufarg, target_ustart + copy_size) &&
23316 DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_this, source_ustart + copy_size)) {
23317 /* Must use memmove() because copy area may overlap (source and target
23318 * buffer may be the same, or from different slices.
23319 */
23320 DUK_MEMMOVE((void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufarg) + target_ustart),
23321 (const void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + source_ustart),
23322 (size_t) copy_size);
23323 } else {
23324 DUK_DDD(DUK_DDDPRINT("buffer copy not covered by underlying buffer(s), ignoring"));
23325 }
23326
23327 silent_ignore:
23328 /* Return value is like write(), number of bytes written.
23329 * The return value matters because of code like:
23330 * "off += buf.copy(...)".
23331 */
23332 duk_push_uint(ctx, copy_size);
23333 return 1;
23334
23335 fail_bounds:
23336 return DUK_RET_RANGE_ERROR;
23337}
23338#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
23339DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) {
23340 DUK_UNREF(ctx);
23341 return DUK_RET_UNSUPPORTED_ERROR;
23342}
23343#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
23344
23345/*
23346 * TypedArray.prototype.set()
23347 *
23348 * TypedArray set() is pretty interesting to implement because:
23349 *
23350 * - The source argument may be a plain array or a typedarray. If the
23351 * source is a TypedArray, values are decoded and re-encoded into the
23352 * target (not as a plain byte copy). This may happen even when the
23353 * element byte size is the same, e.g. integer values may be re-encoded
23354 * into floats.
23355 *
23356 * - Source and target may refer to the same underlying buffer, so that
23357 * the set() operation may overlap. The specification requires that this
23358 * must work as if a copy was made before the operation. Note that this
23359 * is NOT a simple memmove() situation because the source and target
23360 * byte sizes may be different -- e.g. a 4-byte source (Int8Array) may
23361 * expand to a 16-byte target (Uint32Array) so that the target overlaps
23362 * the source both from beginning and the end (unlike in typical memmove).
23363 *
23364 * - Even if 'buf' pointers of the source and target differ, there's no
23365 * guarantee that their memory areas don't overlap. This may be the
23366 * case with external buffers.
23367 *
23368 * Even so, it is nice to optimize for the common case:
23369 *
23370 * - Source and target separate buffers or non-overlapping.
23371 *
23372 * - Source and target have a compatible type so that a plain byte copy
23373 * is possible. Note that while e.g. uint8 and int8 are compatible
23374 * (coercion one way or another doesn't change the byte representation),
23375 * e.g. int8 and uint8clamped are NOT compatible when writing int8
23376 * values into uint8clamped typedarray (-1 would clamp to 0 for instance).
23377 *
23378 * See test-bi-typedarray-proto-set.js.
23379 */
23380
23381#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
23382DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
23383 duk_hthread *thr;
23384 duk_hbufferobject *h_this;
23385 duk_hobject *h_obj;
23386 duk_uarridx_t i, n;
23387 duk_int_t offset_signed;
23388 duk_uint_t offset_elems;
23389 duk_uint_t offset_bytes;
23390
23391 thr = (duk_hthread *) ctx;
23392 DUK_UNREF(thr);
23393
23394 h_this = duk__require_bufobj_this(ctx);
23395 DUK_ASSERT(h_this != NULL);
23396 DUK_ASSERT_HBUFFEROBJECT_VALID(h_this);
23397
23398 if (h_this->buf == NULL) {
23399 DUK_DDD(DUK_DDDPRINT("source neutered, skip copy"));
23400 return 0;
23401 }
23402
23403 h_obj = duk_require_hobject(ctx, 0);
23404 DUK_ASSERT(h_obj != NULL);
23405
23406 /* XXX: V8 throws a TypeError for negative values. Would it
23407 * be more useful to interpret negative offsets here from the
23408 * end of the buffer too?
23409 */
23410 offset_signed = duk_to_int(ctx, 1);
23411 if (offset_signed < 0) {
23412 return DUK_RET_TYPE_ERROR;
23413 }
23414 offset_elems = (duk_uint_t) offset_signed;
23415 offset_bytes = offset_elems << h_this->shift;
23416 if ((offset_bytes >> h_this->shift) != offset_elems) {
23417 /* Byte length would overflow. */
23418 /* XXX: easier check with less code? */
23419 return DUK_RET_RANGE_ERROR;
23420 }
23421 if (offset_bytes > h_this->length) {
23422 /* Equality may be OK but >length not. Checking
23423 * this explicitly avoids some overflow cases
23424 * below.
23425 */
23426 return DUK_RET_RANGE_ERROR;
23427 }
23428 DUK_ASSERT(offset_bytes <= h_this->length);
23429
23430 /* Fast path: source is a TypedArray (or any bufferobject). */
23431
23432 if (DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) {
23433 duk_hbufferobject *h_bufarg;
23434 duk_uint16_t comp_mask;
23435 duk_small_int_t no_overlap = 0;
23436 duk_uint_t src_length;
23437 duk_uint_t dst_length;
23438 duk_uint_t dst_length_elems;
23439 duk_uint8_t *p_src_base;
23440 duk_uint8_t *p_src_end;
23441 duk_uint8_t *p_src;
23442 duk_uint8_t *p_dst_base;
23443 duk_uint8_t *p_dst;
23444 duk_small_uint_t src_elem_size;
23445 duk_small_uint_t dst_elem_size;
23446
23447 h_bufarg = (duk_hbufferobject *) h_obj;
23448 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufarg);
23449
23450 if (h_bufarg->buf == NULL) {
23451 DUK_DDD(DUK_DDDPRINT("target neutered, skip copy"));
23452 return 0;
23453 }
23454
23455 /* Nominal size check. */
23456 src_length = h_bufarg->length; /* bytes in source */
23457 dst_length_elems = (src_length >> h_bufarg->shift); /* elems in source and dest */
23458 dst_length = dst_length_elems << h_this->shift; /* bytes in dest */
23459 if ((dst_length >> h_this->shift) != dst_length_elems) {
23460 /* Byte length would overflow. */
23461 /* XXX: easier check with less code? */
23462 return DUK_RET_RANGE_ERROR;
23463 }
23464 DUK_DDD(DUK_DDDPRINT("nominal size check: src_length=%ld, dst_length=%ld",
23465 (long) src_length, (long) dst_length));
23466 DUK_ASSERT(offset_bytes <= h_this->length);
23467 if (dst_length > h_this->length - offset_bytes) {
23468 /* Overflow not an issue because subtraction is used on the right
23469 * side and guaranteed to be >= 0.
23470 */
23471 DUK_DDD(DUK_DDDPRINT("copy exceeds target buffer nominal length"));
23472 return DUK_RET_RANGE_ERROR;
23473 }
23474 if (!DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_this, offset_bytes + dst_length)) {
23475 DUK_DDD(DUK_DDDPRINT("copy not covered by underlying target buffer, ignore"));
23476 return 0;
23477 }
23478
23479 p_src_base = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufarg);
23480 p_dst_base = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + offset_bytes;
23481
23482 /* Check actual underlying buffers for validity and that they
23483 * cover the copy. No side effects are allowed after the check
23484 * so that the validity status doesn't change.
23485 */
23486 if (!DUK_HBUFFEROBJECT_VALID_SLICE(h_this) ||
23487 !DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg)) {
23488 /* The condition could be more narrow and check for the
23489 * copy area only, but there's no need for fine grained
23490 * behavior when the underlying buffer is misconfigured.
23491 */
23492 DUK_DDD(DUK_DDDPRINT("source and/or target not covered by underlying buffer, skip copy"));
23493 return 0;
23494 }
23495
23496 /* We want to do a straight memory copy if possible: this is
23497 * an important operation because .set() is the TypedArray
23498 * way to copy chunks of memory. However, because set()
23499 * conceptually works in terms of elements, not all views are
23500 * compatible with direct byte copying.
23501 *
23502 * If we do manage a direct copy, the "overlap issue" handled
23503 * below can just be solved using memmove() because the source
23504 * and destination element sizes are necessarily equal.
23505 */
23506
23507 DUK_ASSERT(h_this->elem_type < sizeof(duk__buffer_elemtype_copy_compatible) / sizeof(duk_uint16_t));
23508 comp_mask = duk__buffer_elemtype_copy_compatible[h_this->elem_type];
23509 if (comp_mask & (1 << h_bufarg->elem_type)) {
23510 DUK_ASSERT(src_length == dst_length);
23511
23512 DUK_DDD(DUK_DDDPRINT("fast path: able to use memmove() because views are compatible"));
23513 DUK_MEMMOVE((void *) p_dst_base, (const void *) p_src_base, (size_t) dst_length);
23514 return 0;
23515 }
23516 DUK_DDD(DUK_DDDPRINT("fast path: views are not compatible with a byte copy, copy by item"));
23517
23518 /* We want to avoid making a copy to process set() but that's
23519 * not always possible: the source and the target may overlap
23520 * and because element sizes are different, the overlap cannot
23521 * always be handled with a memmove() or choosing the copy
23522 * direction in a certain way. For example, if source type is
23523 * uint8 and target type is uint32, the target area may exceed
23524 * the source area from both ends!
23525 *
23526 * Note that because external buffers may point to the same
23527 * memory areas, we must ultimately make this check using
23528 * pointers.
23529 *
23530 * NOTE: careful with side effects: any side effect may cause
23531 * a buffer resize (or external buffer pointer/length update)!
23532 */
23533
23534 DUK_DDD(DUK_DDDPRINT("overlap check: p_src_base=%p, src_length=%ld, "
23535 "p_dst_base=%p, dst_length=%ld",
23536 (void *) p_src_base, (long) src_length,
23537 (void *) p_dst_base, (long) dst_length));
23538
23539 if (p_src_base >= p_dst_base + dst_length || /* source starts after dest ends */
23540 p_src_base + src_length <= p_dst_base) { /* source ends before dest starts */
23541 no_overlap = 1;
23542 }
23543
23544 if (!no_overlap) {
23545 /* There's overlap: the desired end result is that
23546 * conceptually a copy is made to avoid "trampling"
23547 * of source data by destination writes. We make
23548 * an actual temporary copy to handle this case.
23549 */
23550 duk_uint8_t *p_src_copy;
23551
23552 DUK_DDD(DUK_DDDPRINT("there is overlap, make a copy of the source"));
23553 p_src_copy = (duk_uint8_t *) duk_push_fixed_buffer(ctx, src_length);
23554 DUK_ASSERT(p_src_copy != NULL);
23555 DUK_MEMCPY((void *) p_src_copy, (const void *) p_src_base, (size_t) src_length);
23556
23557 p_src_base = p_src_copy; /* use p_src_base from now on */
23558 }
23559 /* Value stack intentionally mixed size here. */
23560
23561 DUK_DDD(DUK_DDDPRINT("after overlap check: p_src_base=%p, src_length=%ld, "
23562 "p_dst_base=%p, dst_length=%ld, valstack top=%ld",
23563 (void *) p_src_base, (long) src_length,
23564 (void *) p_dst_base, (long) dst_length,
23565 (long) duk_get_top(ctx)));
23566
23567 /* Ready to make the copy. We must proceed element by element
23568 * and must avoid any side effects that might cause the buffer
23569 * validity check above to become invalid.
23570 *
23571 * Although we work through the value stack here, only plain
23572 * numbers are handled which should be side effect safe.
23573 */
23574
23575 src_elem_size = 1 << h_bufarg->shift;
23576 dst_elem_size = 1 << h_this->shift;
23577 p_src = p_src_base;
23578 p_dst = p_dst_base;
23579 p_src_end = p_src_base + src_length;
23580
23581 while (p_src != p_src_end) {
23582 DUK_DDD(DUK_DDDPRINT("fast path per element copy loop: "
23583 "p_src=%p, p_src_end=%p, p_dst=%p",
23584 (void *) p_src, (void *) p_src_end, (void *) p_dst));
23585 /* A validated read() is always a number, so it's write coercion
23586 * is always side effect free an won't invalidate pointers etc.
23587 */
23588 duk_hbufferobject_push_validated_read(ctx, h_bufarg, p_src, src_elem_size);
23589 duk_hbufferobject_validated_write(ctx, h_this, p_dst, dst_elem_size);
23590 duk_pop(ctx);
23591 p_src += src_elem_size;
23592 p_dst += dst_elem_size;
23593 }
23594
23595 return 0;
23596 } else {
23597 /* Slow path: quite slow, but we save space by using the property code
23598 * to write coerce target values. We don't need to worry about overlap
23599 * here because the source is not a TypedArray.
23600 *
23601 * We could use the bufferobject write coercion helper but since the
23602 * property read may have arbitrary side effects, full validity checks
23603 * would be needed for every element anyway.
23604 */
23605
23606 n = (duk_uarridx_t) duk_get_length(ctx, 0);
23607 DUK_ASSERT(offset_bytes <= h_this->length);
23608 if ((n << h_this->shift) > h_this->length - offset_bytes) {
23609 /* Overflow not an issue because subtraction is used on the right
23610 * side and guaranteed to be >= 0.
23611 */
23612 DUK_DDD(DUK_DDDPRINT("copy exceeds target buffer nominal length"));
23613 return DUK_RET_RANGE_ERROR;
23614 }
23615
23616 /* There's no need to check for buffer validity status for the
23617 * target here: the property access code will do that for each
23618 * element. Moreover, if we did check the validity here, side
23619 * effects from reading the source argument might invalidate
23620 * the results anyway.
23621 */
23622
23623 DUK_ASSERT_TOP(ctx, 2);
23624 duk_push_this(ctx);
23625
23626 for (i = 0; i < n; i++) {
23627 duk_get_prop_index(ctx, 0, i);
23628 duk_put_prop_index(ctx, 2, offset_elems + i);
23629 }
23630 }
23631
23632 return 0;
23633}
23634#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
23635DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
23636 DUK_UNREF(ctx);
23637 return DUK_RET_UNSUPPORTED_ERROR;
23638}
23639#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
23640
23641/*
23642 * Node.js Buffer.prototype.slice([start], [end])
23643 * ArrayBuffer.prototype.slice(begin, [end])
23644 * TypedArray.prototype.slice(begin, [end])
23645 *
23646 * The API calls are almost identical; negative indices are counted from end
23647 * of buffer, and final indices are clamped (allowing crossed indices). Main
23648 * differences:
23649 *
23650 * - Copy/view behavior; Node.js .slice() and TypedArray .subarray() create
23651 * views, ArrayBuffer .slice() creates a copy
23652 *
23653 * - Resulting object has a different class and prototype depending on the
23654 * call (or 'this' argument)
23655 *
23656 * - TypedArray .subarray() arguments are element indices, not byte offsets
23657 */
23658
23659#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
23660DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) {
23661 duk_hthread *thr;
23662 duk_small_int_t magic;
23663 duk_small_uint_t res_class_num;
23664 duk_hobject *res_proto;
23665 duk_hbufferobject *h_this;
23666 duk_hbufferobject *h_bufobj;
23667 duk_hbuffer *h_val;
23668 duk_int_t start_offset, end_offset;
23669 duk_uint_t slice_length;
23670
23671 thr = (duk_hthread *) ctx;
23672 DUK_UNREF(thr);
23673
23674 /* [ start end ] */
23675
23676 magic = duk_get_current_magic(ctx);
23677 h_this = duk__require_bufobj_this(ctx);
23678
23679 /* Slice offsets are element (not byte) offsets, which only matters
23680 * for TypedArray views, Node.js Buffer and ArrayBuffer have shift
23681 * zero so byte and element offsets are the same. Negative indices
23682 * are counted from end of slice, crossed indices are allowed (and
23683 * result in zero length result), and final values are clamped
23684 * against the current slice. There's intentionally no check
23685 * against the underlying buffer here.
23686 */
23687
23688 duk__clamp_startend_negidx_shifted(ctx, h_this, 0 /*idx_start*/, 1 /*idx_end*/, &start_offset, &end_offset);
23689 DUK_ASSERT(end_offset >= start_offset);
23690 slice_length = (duk_uint_t) (end_offset - start_offset);
23691
23692 /* The resulting buffer object gets the same class and prototype as
23693 * the buffer in 'this', e.g. if the input is a Node.js Buffer the
23694 * result is a Node.js Buffer; if the input is a Float32Array, the
23695 * result is a Float32Array.
23696 *
23697 * For the class number this seems correct. The internal prototype
23698 * is not so clear: if 'this' is a bufferobject with a non-standard
23699 * prototype object, that value gets copied over into the result
23700 * (instead of using the standard prototype for that object type).
23701 */
23702
23703 res_class_num = DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_this);
23704 h_bufobj = duk_push_bufferobject_raw(ctx,
23705 DUK_HOBJECT_FLAG_EXTENSIBLE |
23706 DUK_HOBJECT_FLAG_BUFFEROBJECT |
23707 DUK_HOBJECT_CLASS_AS_FLAGS(res_class_num),
23708 DUK_BIDX_OBJECT_PROTOTYPE); /* replaced */
23709 DUK_ASSERT(h_bufobj != NULL);
23710 res_proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_this); /* may be NULL */
23711 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) h_bufobj, res_proto);
23712
11fdf7f2 23713 DUK_ASSERT(h_bufobj->length == 0);
7c673cae
FG
23714 h_bufobj->shift = h_this->shift; /* inherit */
23715 h_bufobj->elem_type = h_this->elem_type; /* inherit */
23716 h_bufobj->is_view = magic & 0x01;
23717 DUK_ASSERT(h_bufobj->is_view == 0 || h_bufobj->is_view == 1);
23718
23719 h_val = h_this->buf;
23720 if (h_val == NULL) {
23721 return DUK_RET_TYPE_ERROR;
23722 }
23723
23724 if (magic & 0x02) {
23725 /* non-zero: make copy */
23726 duk_uint8_t *p_copy;
23727 duk_size_t copy_length;
23728
23729 p_copy = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) slice_length);
23730 DUK_ASSERT(p_copy != NULL);
23731
23732 /* Copy slice, respecting underlying buffer limits; remainder
23733 * is left as zero.
23734 */
23735 copy_length = DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h_this, slice_length);
23736 DUK_MEMCPY((void *) p_copy,
23737 (const void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
23738 copy_length);
23739
23740 h_val = duk_get_hbuffer(ctx, -1);
23741 DUK_ASSERT(h_val != NULL);
23742
23743 h_bufobj->buf = h_val;
23744 DUK_HBUFFER_INCREF(thr, h_val);
11fdf7f2 23745 h_bufobj->length = slice_length;
7c673cae
FG
23746 DUK_ASSERT(h_bufobj->offset == 0);
23747
23748 duk_pop(ctx); /* reachable so pop OK */
23749 } else {
23750 h_bufobj->buf = h_val;
23751 DUK_HBUFFER_INCREF(thr, h_val);
11fdf7f2 23752 h_bufobj->length = slice_length;
7c673cae
FG
23753 h_bufobj->offset = (duk_uint_t) (h_this->offset + start_offset);
23754
23755 /* Copy the .buffer property, needed for TypedArray.prototype.subarray().
23756 *
23757 * XXX: limit copy only for TypedArray classes specifically?
23758 */
23759
23760 duk_push_this(ctx);
23761 if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LC_BUFFER)) {
23762 duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE);
23763 duk_pop(ctx);
23764 } else {
23765 duk_pop_2(ctx);
23766 }
23767 }
23768 /* unbalanced stack on purpose */
23769
23770 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
23771 return 1;
23772}
23773#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
23774DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) {
23775 DUK_UNREF(ctx);
23776 return DUK_RET_UNSUPPORTED_ERROR;
23777}
23778#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
23779
23780/*
23781 * Node.js Buffer.isEncoding()
23782 */
23783
23784#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
23785DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx) {
23786 const char *encoding;
23787
23788 /* only accept lowercase 'utf8' now. */
23789
23790 encoding = duk_to_string(ctx, 0);
23791 DUK_ASSERT(duk_is_string(ctx, 0)); /* guaranteed by duk_to_string() */
23792 duk_push_boolean(ctx, DUK_STRCMP(encoding, "utf8") == 0);
23793 return 1;
23794}
23795#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
23796DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx) {
23797 DUK_UNREF(ctx);
23798 return DUK_RET_UNSUPPORTED_ERROR;
23799}
23800#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
23801
23802/*
23803 * Node.js Buffer.isBuffer()
23804 */
23805
23806#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
23807DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx) {
23808 duk_hthread *thr;
23809 duk_tval *tv;
23810 duk_hobject *h;
23811 duk_hobject *h_proto;
23812 duk_bool_t ret = 0;
23813
23814 thr = (duk_hthread *) ctx;
23815
23816 DUK_ASSERT(duk_get_top(ctx) >= 1); /* nargs */
23817 tv = duk_get_tval(ctx, 0);
23818 DUK_ASSERT(tv != NULL);
23819
23820 if (DUK_TVAL_IS_OBJECT(tv)) {
23821 h = DUK_TVAL_GET_OBJECT(tv);
23822 DUK_ASSERT(h != NULL);
23823
23824 h_proto = thr->builtins[DUK_BIDX_NODEJS_BUFFER_PROTOTYPE];
23825 DUK_ASSERT(h_proto != NULL);
23826
23827 h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
23828 if (h) {
23829 ret = duk_hobject_prototype_chain_contains(thr, h, h_proto, 0 /*ignore_loop*/);
23830 }
23831 }
23832
23833 duk_push_boolean(ctx, ret);
23834 return 1;
23835}
23836#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
23837DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx) {
23838 DUK_UNREF(ctx);
23839 return DUK_RET_UNSUPPORTED_ERROR;
23840}
23841#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
23842
23843/*
23844 * Node.js Buffer.byteLength()
23845 */
23846
23847#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
23848DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx) {
23849 const char *str;
23850 duk_size_t len;
23851
23852 /* At the moment Buffer(<str>) will just use the string bytes as
23853 * is (ignoring encoding), so we return the string length here
23854 * unconditionally.
23855 */
23856
23857 str = duk_to_lstring(ctx, 0, &len);
23858 DUK_UNREF(str);
23859 duk_push_size_t(ctx, len);
23860 return 1;
23861}
23862#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
23863DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx) {
23864 DUK_UNREF(ctx);
23865 return DUK_RET_UNSUPPORTED_ERROR;
23866}
23867#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
23868
23869/*
23870 * Node.js Buffer.concat()
23871 */
23872
23873#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
23874DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) {
23875 duk_hthread *thr;
23876 duk_hobject *h_arg;
23877 duk_int_t total_length = 0;
23878 duk_hbufferobject *h_bufobj;
23879 duk_hbufferobject *h_bufres;
23880 duk_hbuffer *h_val;
23881 duk_uint_t i, n;
23882 duk_uint8_t *p;
23883 duk_size_t space_left;
23884 duk_size_t copy_size;
23885
23886 thr = (duk_hthread *) ctx;
23887 DUK_UNREF(thr);
23888
23889 /* Node.js accepts only actual Arrays. */
23890 h_arg = duk_require_hobject(ctx, 0);
23891 if (DUK_HOBJECT_GET_CLASS_NUMBER(h_arg) != DUK_HOBJECT_CLASS_ARRAY) {
23892 return DUK_RET_TYPE_ERROR;
23893 }
23894
23895 /* Compute result length and validate argument buffers. */
23896 n = (duk_uint_t) duk_get_length(ctx, 0);
23897 for (i = 0; i < n; i++) {
23898 /* Neutered checks not necessary here: neutered buffers have
23899 * zero 'length' so we'll effectively skip them.
23900 */
23901 DUK_ASSERT_TOP(ctx, 2); /* [ array totalLength ] */
23902 duk_get_prop_index(ctx, 0, (duk_uarridx_t) i); /* -> [ array totalLength buf ] */
23903 h_bufobj = duk__require_bufobj_value(ctx, 2);
23904 DUK_ASSERT(h_bufobj != NULL);
23905 total_length += h_bufobj->length;
23906 duk_pop(ctx);
23907 }
23908 if (n == 1) {
23909 /* For the case n==1 Node.js doesn't seem to type check
23910 * the sole member but we do it before returning it.
23911 * For this case only the original buffer object is
23912 * returned (not a copy).
23913 */
23914 duk_get_prop_index(ctx, 0, 0);
23915 return 1;
23916 }
23917
23918 /* User totalLength overrides a computed length, but we'll check
23919 * every copy in the copy loop. Note that duk_to_uint() can
23920 * technically have arbitrary side effects so we need to recheck
23921 * the buffers in the copy loop.
23922 */
23923 if (!duk_is_undefined(ctx, 1) && n > 0) {
23924 /* For n == 0, Node.js ignores totalLength argument and
23925 * returns a zero length buffer.
23926 */
23927 total_length = duk_to_int(ctx, 1);
23928 }
23929 if (total_length < 0) {
23930 return DUK_RET_RANGE_ERROR;
23931 }
23932
23933 h_bufres = duk_push_bufferobject_raw(ctx,
23934 DUK_HOBJECT_FLAG_EXTENSIBLE |
23935 DUK_HOBJECT_FLAG_BUFFEROBJECT |
23936 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER),
23937 DUK_BIDX_NODEJS_BUFFER_PROTOTYPE);
23938 DUK_ASSERT(h_bufres != NULL);
23939
23940 p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, total_length);
23941 DUK_ASSERT(p != NULL);
23942 space_left = total_length;
23943
23944 for (i = 0; i < n; i++) {
23945 DUK_ASSERT_TOP(ctx, 4); /* [ array totalLength bufres buf ] */
23946
23947 duk_get_prop_index(ctx, 0, (duk_uarridx_t) i);
23948 h_bufobj = duk__require_bufobj_value(ctx, 4);
23949 DUK_ASSERT(h_bufobj != NULL);
23950
23951 copy_size = h_bufobj->length;
23952 if (copy_size > space_left) {
23953 copy_size = space_left;
23954 }
23955
23956 if (h_bufobj->buf != NULL &&
23957 DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj)) {
23958 DUK_MEMCPY((void *) p,
23959 (const void *) DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufobj),
23960 copy_size);
23961 } else {
23962 /* Just skip, leaving zeroes in the result. */
23963 ;
23964 }
23965 p += copy_size;
23966 space_left -= copy_size;
23967
23968 duk_pop(ctx);
23969 }
23970
23971 h_val = duk_get_hbuffer(ctx, -1);
23972 DUK_ASSERT(h_val != NULL);
23973
23974 duk__set_bufobj_buffer(ctx, h_bufres, h_val);
23975 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufres);
23976
23977 duk_pop(ctx); /* pop plain buffer, now reachable through h_bufres */
23978
23979 return 1; /* return h_bufres */
23980}
23981#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
23982DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) {
23983 DUK_UNREF(ctx);
23984 return DUK_RET_UNSUPPORTED_ERROR;
23985}
23986#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
23987
23988/*
23989 * Shared readfield and writefield methods
23990 *
23991 * The readfield/writefield methods need support for endianness and field
23992 * types. All offsets are byte based so no offset shifting is needed.
23993 */
23994
23995#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
23996/* Format of magic, bits:
23997 * 0...1: field type; 0=uint8, 1=uint16, 2=uint32, 3=float, 4=double, 5=unused, 6=unused, 7=unused
23998 * 3: endianness: 0=little, 1=big
23999 * 4: signed: 1=yes, 0=no
24000 * 5: typedarray: 1=yes, 0=no
24001 */
24002#define DUK__FLD_8BIT 0
24003#define DUK__FLD_16BIT 1
24004#define DUK__FLD_32BIT 2
24005#define DUK__FLD_FLOAT 3
24006#define DUK__FLD_DOUBLE 4
24007#define DUK__FLD_VARINT 5
24008#define DUK__FLD_BIGENDIAN (1 << 3)
24009#define DUK__FLD_SIGNED (1 << 4)
24010#define DUK__FLD_TYPEDARRAY (1 << 5)
24011
24012/* XXX: split into separate functions for each field type? */
24013DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
24014 duk_hthread *thr;
24015 duk_small_int_t magic = (duk_small_int_t) duk_get_current_magic(ctx);
24016 duk_small_int_t magic_ftype;
24017 duk_small_int_t magic_bigendian;
24018 duk_small_int_t magic_signed;
24019 duk_small_int_t magic_typedarray;
24020 duk_small_int_t endswap;
24021 duk_hbufferobject *h_this;
24022 duk_bool_t no_assert;
24023 duk_int_t offset_signed;
24024 duk_uint_t offset;
24025 duk_uint_t buffer_length;
24026 duk_uint_t check_length;
24027 duk_uint8_t *buf;
24028 duk_double_union du;
24029
24030 thr = (duk_hthread *) ctx;
24031 DUK_UNREF(thr);
24032
24033 magic_ftype = magic & 0x0007;
24034 magic_bigendian = magic & 0x0008;
24035 magic_signed = magic & 0x0010;
24036 magic_typedarray = magic & 0x0020;
24037
24038 h_this = duk__require_bufobj_this(ctx);
24039 DUK_ASSERT(h_this != NULL);
24040 buffer_length = h_this->length;
24041
24042 /* [ offset noAssert ], when ftype != DUK__FLD_VARINT */
24043 /* [ offset fieldByteLength noAssert ], when ftype == DUK__FLD_VARINT */
24044 /* [ offset littleEndian ], when DUK__FLD_TYPEDARRAY (regardless of ftype) */
24045
24046 /* Handle TypedArray vs. Node.js Buffer arg differences */
24047 if (magic_typedarray) {
24048 no_assert = 0;
24049#if defined(DUK_USE_INTEGER_LE)
24050 endswap = !duk_to_boolean(ctx, 1); /* 1=little endian */
24051#else
24052 endswap = duk_to_boolean(ctx, 1); /* 1=little endian */
24053#endif
24054 } else {
24055 no_assert = duk_to_boolean(ctx, (magic_ftype == DUK__FLD_VARINT) ? 2 : 1);
24056#if defined(DUK_USE_INTEGER_LE)
24057 endswap = magic_bigendian;
24058#else
24059 endswap = !magic_bigendian;
24060#endif
24061 }
24062
24063 /* Offset is coerced first to signed integer range and then to unsigned.
24064 * This ensures we can add a small byte length (1-8) to the offset in
24065 * bound checks and not wrap.
24066 */
24067 offset_signed = duk_to_int(ctx, 0);
24068 offset = (duk_uint_t) offset_signed;
24069 if (offset_signed < 0) {
24070 goto fail_bounds;
24071 }
24072
24073 DUK_DDD(DUK_DDDPRINT("readfield, buffer_length=%ld, offset=%ld, no_assert=%d, "
24074 "magic=%04x, magic_fieldtype=%d, magic_bigendian=%d, magic_signed=%d, "
24075 "endswap=%d",
24076 (long) buffer_length, (long) offset, (int) no_assert,
24077 (unsigned int) magic, (int) magic_ftype, (int) (magic_bigendian >> 3),
24078 (int) (magic_signed >> 4), (int) endswap));
24079
24080 /* Update 'buffer_length' to be the effective, safe limit which
24081 * takes into account the underlying buffer. This value will be
24082 * potentially invalidated by any side effect.
24083 */
24084 check_length = DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h_this, buffer_length);
24085 DUK_DDD(DUK_DDDPRINT("buffer_length=%ld, check_length=%ld",
24086 (long) buffer_length, (long) check_length));
24087
24088 if (h_this->buf) {
24089 buf = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this);
24090 } else {
11fdf7f2
TL
24091 /* Neutered. We could go into the switch-case safely with
24092 * buf == NULL because check_length == 0. To avoid scanbuild
24093 * warnings, fail directly instead.
24094 */
7c673cae 24095 DUK_ASSERT(check_length == 0);
11fdf7f2 24096 goto fail_neutered;
7c673cae 24097 }
11fdf7f2 24098 DUK_ASSERT(buf != NULL);
7c673cae
FG
24099
24100 switch (magic_ftype) {
24101 case DUK__FLD_8BIT: {
24102 duk_uint8_t tmp;
24103 if (offset + 1U > check_length) {
24104 goto fail_bounds;
24105 }
24106 tmp = buf[offset];
24107 if (magic_signed) {
24108 duk_push_int(ctx, (duk_int_t) ((duk_int8_t) tmp));
24109 } else {
24110 duk_push_uint(ctx, (duk_uint_t) tmp);
24111 }
24112 break;
24113 }
24114 case DUK__FLD_16BIT: {
24115 duk_uint16_t tmp;
24116 if (offset + 2U > check_length) {
24117 goto fail_bounds;
24118 }
24119 DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 2);
24120 tmp = du.us[0];
24121 if (endswap) {
24122 tmp = DUK_BSWAP16(tmp);
24123 }
24124 if (magic_signed) {
24125 duk_push_int(ctx, (duk_int_t) ((duk_int16_t) tmp));
24126 } else {
24127 duk_push_uint(ctx, (duk_uint_t) tmp);
24128 }
24129 break;
24130 }
24131 case DUK__FLD_32BIT: {
24132 duk_uint32_t tmp;
24133 if (offset + 4U > check_length) {
24134 goto fail_bounds;
24135 }
24136 DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 4);
24137 tmp = du.ui[0];
24138 if (endswap) {
24139 tmp = DUK_BSWAP32(tmp);
24140 }
24141 if (magic_signed) {
24142 duk_push_int(ctx, (duk_int_t) ((duk_int32_t) tmp));
24143 } else {
24144 duk_push_uint(ctx, (duk_uint_t) tmp);
24145 }
24146 break;
24147 }
24148 case DUK__FLD_FLOAT: {
24149 duk_uint32_t tmp;
24150 if (offset + 4U > check_length) {
24151 goto fail_bounds;
24152 }
24153 DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 4);
24154 if (endswap) {
24155 tmp = du.ui[0];
24156 tmp = DUK_BSWAP32(tmp);
24157 du.ui[0] = tmp;
24158 }
24159 duk_push_number(ctx, (duk_double_t) du.f[0]);
24160 break;
24161 }
24162 case DUK__FLD_DOUBLE: {
24163 if (offset + 8U > check_length) {
24164 goto fail_bounds;
24165 }
24166 DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 8);
24167 if (endswap) {
24168 DUK_DBLUNION_BSWAP64(&du);
24169 }
24170 duk_push_number(ctx, (duk_double_t) du.d);
24171 break;
24172 }
24173 case DUK__FLD_VARINT: {
24174 /* Node.js Buffer variable width integer field. We don't really
24175 * care about speed here, so aim for shortest algorithm.
24176 */
24177 duk_int_t field_bytelen;
24178 duk_int_t i, i_step, i_end;
24179#if defined(DUK_USE_64BIT_OPS)
24180 duk_int64_t tmp;
24181 duk_small_uint_t shift_tmp;
24182#else
24183 duk_double_t tmp;
24184 duk_small_int_t highbyte;
24185#endif
24186 const duk_uint8_t *p;
24187
24188 field_bytelen = duk_get_int(ctx, 1); /* avoid side effects! */
24189 if (field_bytelen < 1 || field_bytelen > 6) {
24190 goto fail_field_length;
24191 }
24192 if (offset + (duk_uint_t) field_bytelen > check_length) {
24193 goto fail_bounds;
24194 }
24195 p = (const duk_uint8_t *) (buf + offset);
24196
24197 /* Slow gathering of value using either 64-bit arithmetic
24198 * or IEEE doubles if 64-bit types not available. Handling
24199 * of negative numbers is a bit non-obvious in both cases.
24200 */
24201
24202 if (magic_bigendian) {
24203 /* Gather in big endian */
24204 i = 0;
24205 i_step = 1;
24206 i_end = field_bytelen; /* one i_step over */
24207 } else {
24208 /* Gather in little endian */
24209 i = field_bytelen - 1;
24210 i_step = -1;
24211 i_end = -1; /* one i_step over */
24212 }
24213
24214#if defined(DUK_USE_64BIT_OPS)
24215 tmp = 0;
24216 do {
24217 DUK_ASSERT(i >= 0 && i < field_bytelen);
24218 tmp = (tmp << 8) + (duk_int64_t) p[i];
24219 i += i_step;
24220 } while (i != i_end);
24221
24222 if (magic_signed) {
24223 /* Shift to sign extend. */
24224 shift_tmp = 64 - (field_bytelen * 8);
24225 tmp = (tmp << shift_tmp) >> shift_tmp;
24226 }
24227
24228 duk_push_i64(ctx, tmp);
24229#else
24230 highbyte = p[i];
24231 if (magic_signed && (highbyte & 0x80) != 0) {
24232 /* 0xff => 255 - 256 = -1; 0x80 => 128 - 256 = -128 */
24233 tmp = (duk_double_t) (highbyte - 256);
24234 } else {
24235 tmp = (duk_double_t) highbyte;
24236 }
24237 for (;;) {
24238 i += i_step;
24239 if (i == i_end) {
24240 break;
24241 }
24242 DUK_ASSERT(i >= 0 && i < field_bytelen);
24243 tmp = (tmp * 256.0) + (duk_double_t) p[i];
24244 }
24245
24246 duk_push_number(ctx, tmp);
24247#endif
24248 break;
24249 }
24250 default: { /* should never happen but default here */
24251 goto fail_bounds;
24252 }
24253 }
24254
24255 return 1;
24256
11fdf7f2 24257 fail_neutered:
7c673cae
FG
24258 fail_field_length:
24259 fail_bounds:
24260 if (no_assert) {
24261 /* Node.js return value for noAssert out-of-bounds reads is
24262 * usually (but not always) NaN. Return NaN consistently.
24263 */
24264 duk_push_nan(ctx);
24265 return 1;
24266 }
24267
24268 return DUK_RET_RANGE_ERROR;
24269}
24270#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
24271DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
24272 DUK_UNREF(ctx);
24273 return DUK_RET_UNSUPPORTED_ERROR;
24274}
24275#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
24276
24277#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
24278/* XXX: split into separate functions for each field type? */
24279DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
24280 duk_hthread *thr;
24281 duk_small_int_t magic = (duk_small_int_t) duk_get_current_magic(ctx);
24282 duk_small_int_t magic_ftype;
24283 duk_small_int_t magic_bigendian;
24284 duk_small_int_t magic_signed;
24285 duk_small_int_t magic_typedarray;
24286 duk_small_int_t endswap;
24287 duk_hbufferobject *h_this;
24288 duk_bool_t no_assert;
24289 duk_int_t offset_signed;
24290 duk_uint_t offset;
24291 duk_uint_t buffer_length;
24292 duk_uint_t check_length;
24293 duk_uint8_t *buf;
24294 duk_double_union du;
24295 duk_int_t nbytes = 0;
24296
24297 thr = (duk_hthread *) ctx;
24298 DUK_UNREF(thr);
24299
24300 magic_ftype = magic & 0x0007;
24301 magic_bigendian = magic & 0x0008;
24302 magic_signed = magic & 0x0010;
24303 magic_typedarray = magic & 0x0020;
24304 DUK_UNREF(magic_signed);
24305
24306 h_this = duk__require_bufobj_this(ctx);
24307 DUK_ASSERT(h_this != NULL);
24308 buffer_length = h_this->length;
24309
24310 /* [ value offset noAssert ], when ftype != DUK__FLD_VARINT */
24311 /* [ value offset fieldByteLength noAssert ], when ftype == DUK__FLD_VARINT */
24312 /* [ offset value littleEndian ], when DUK__FLD_TYPEDARRAY (regardless of ftype) */
24313
24314 /* Handle TypedArray vs. Node.js Buffer arg differences */
24315 if (magic_typedarray) {
24316 no_assert = 0;
24317#if defined(DUK_USE_INTEGER_LE)
24318 endswap = !duk_to_boolean(ctx, 2); /* 1=little endian */
24319#else
24320 endswap = duk_to_boolean(ctx, 2); /* 1=little endian */
24321#endif
24322 duk_swap(ctx, 0, 1); /* offset/value order different from Node.js */
24323 } else {
24324 no_assert = duk_to_boolean(ctx, (magic_ftype == DUK__FLD_VARINT) ? 3 : 2);
24325#if defined(DUK_USE_INTEGER_LE)
24326 endswap = magic_bigendian;
24327#else
24328 endswap = !magic_bigendian;
24329#endif
24330 }
24331
24332 /* Offset is coerced first to signed integer range and then to unsigned.
24333 * This ensures we can add a small byte length (1-8) to the offset in
24334 * bound checks and not wrap.
24335 */
24336 offset_signed = duk_to_int(ctx, 1);
24337 offset = (duk_uint_t) offset_signed;
24338
24339 /* We need 'nbytes' even for a failed offset; return value must be
24340 * (offset + nbytes) even when write fails due to invalid offset.
24341 */
24342 if (magic_ftype != DUK__FLD_VARINT) {
24343 DUK_ASSERT(magic_ftype >= 0 && magic_ftype < (duk_small_int_t) (sizeof(duk__buffer_nbytes_from_fldtype) / sizeof(duk_uint8_t)));
24344 nbytes = duk__buffer_nbytes_from_fldtype[magic_ftype];
24345 } else {
24346 nbytes = duk_get_int(ctx, 2);
24347 if (nbytes < 1 || nbytes > 6) {
24348 goto fail_field_length;
24349 }
24350 }
24351 DUK_ASSERT(nbytes >= 1 && nbytes <= 8);
24352
24353 /* Now we can check offset validity. */
24354 if (offset_signed < 0) {
24355 goto fail_bounds;
24356 }
24357
24358 DUK_DDD(DUK_DDDPRINT("writefield, value=%!T, buffer_length=%ld, offset=%ld, no_assert=%d, "
24359 "magic=%04x, magic_fieldtype=%d, magic_bigendian=%d, magic_signed=%d, "
24360 "endswap=%d",
24361 duk_get_tval(ctx, 0), (long) buffer_length, (long) offset, (int) no_assert,
24362 (unsigned int) magic, (int) magic_ftype, (int) (magic_bigendian >> 3),
24363 (int) (magic_signed >> 4), (int) endswap));
24364
24365 /* Coerce value to a number before computing check_length, so that
24366 * the field type specific coercion below can't have side effects
24367 * that would invalidate check_length.
24368 */
24369 duk_to_number(ctx, 0);
24370
24371 /* Update 'buffer_length' to be the effective, safe limit which
24372 * takes into account the underlying buffer. This value will be
24373 * potentially invalidated by any side effect.
24374 */
24375 check_length = DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h_this, buffer_length);
24376 DUK_DDD(DUK_DDDPRINT("buffer_length=%ld, check_length=%ld",
24377 (long) buffer_length, (long) check_length));
24378
24379 if (h_this->buf) {
24380 buf = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this);
24381 } else {
11fdf7f2
TL
24382 /* Neutered. We could go into the switch-case safely with
24383 * buf == NULL because check_length == 0. To avoid scanbuild
24384 * warnings, fail directly instead.
24385 */
7c673cae 24386 DUK_ASSERT(check_length == 0);
11fdf7f2 24387 goto fail_neutered;
7c673cae 24388 }
11fdf7f2 24389 DUK_ASSERT(buf != NULL);
7c673cae
FG
24390
24391 switch (magic_ftype) {
24392 case DUK__FLD_8BIT: {
24393 if (offset + 1U > check_length) {
24394 goto fail_bounds;
24395 }
24396 /* sign doesn't matter when writing */
24397 buf[offset] = (duk_uint8_t) duk_to_uint32(ctx, 0);
24398 break;
24399 }
24400 case DUK__FLD_16BIT: {
24401 duk_uint16_t tmp;
24402 if (offset + 2U > check_length) {
24403 goto fail_bounds;
24404 }
24405 tmp = (duk_uint16_t) duk_to_uint32(ctx, 0);
24406 if (endswap) {
24407 tmp = DUK_BSWAP16(tmp);
24408 }
24409 du.us[0] = tmp;
24410 /* sign doesn't matter when writing */
24411 DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 2);
24412 break;
24413 }
24414 case DUK__FLD_32BIT: {
24415 duk_uint32_t tmp;
24416 if (offset + 4U > check_length) {
24417 goto fail_bounds;
24418 }
24419 tmp = (duk_uint32_t) duk_to_uint32(ctx, 0);
24420 if (endswap) {
24421 tmp = DUK_BSWAP32(tmp);
24422 }
24423 du.ui[0] = tmp;
24424 /* sign doesn't matter when writing */
24425 DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 4);
24426 break;
24427 }
24428 case DUK__FLD_FLOAT: {
24429 duk_uint32_t tmp;
24430 if (offset + 4U > check_length) {
24431 goto fail_bounds;
24432 }
24433 du.f[0] = (duk_float_t) duk_to_number(ctx, 0);
24434 if (endswap) {
24435 tmp = du.ui[0];
24436 tmp = DUK_BSWAP32(tmp);
24437 du.ui[0] = tmp;
24438 }
24439 /* sign doesn't matter when writing */
24440 DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 4);
24441 break;
24442 }
24443 case DUK__FLD_DOUBLE: {
24444 if (offset + 8U > check_length) {
24445 goto fail_bounds;
24446 }
24447 du.d = (duk_double_t) duk_to_number(ctx, 0);
24448 if (endswap) {
24449 DUK_DBLUNION_BSWAP64(&du);
24450 }
24451 /* sign doesn't matter when writing */
24452 DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 8);
24453 break;
24454 }
24455 case DUK__FLD_VARINT: {
24456 /* Node.js Buffer variable width integer field. We don't really
24457 * care about speed here, so aim for shortest algorithm.
24458 */
24459 duk_int_t field_bytelen;
24460 duk_int_t i, i_step, i_end;
24461#if defined(DUK_USE_64BIT_OPS)
24462 duk_int64_t tmp;
24463#else
24464 duk_double_t tmp;
24465#endif
24466 duk_uint8_t *p;
24467
24468 field_bytelen = (duk_int_t) nbytes;
24469 if (offset + (duk_uint_t) field_bytelen > check_length) {
24470 goto fail_bounds;
24471 }
24472
24473 /* Slow writing of value using either 64-bit arithmetic
24474 * or IEEE doubles if 64-bit types not available. There's
24475 * no special sign handling when writing varints.
24476 */
24477
24478 if (magic_bigendian) {
24479 /* Write in big endian */
24480 i = field_bytelen; /* one i_step added at top of loop */
24481 i_step = -1;
24482 i_end = 0;
24483 } else {
24484 /* Write in little endian */
24485 i = -1; /* one i_step added at top of loop */
24486 i_step = 1;
24487 i_end = field_bytelen - 1;
24488 }
24489
24490 /* XXX: The duk_to_number() cast followed by integer coercion
24491 * is platform specific so NaN, +/- Infinity, and out-of-bounds
24492 * values result in platform specific output now.
24493 * See: test-bi-nodejs-buffer-proto-varint-special.js
24494 */
24495
24496#if defined(DUK_USE_64BIT_OPS)
24497 tmp = (duk_int64_t) duk_to_number(ctx, 0);
24498 p = (duk_uint8_t *) (buf + offset);
24499 do {
24500 i += i_step;
24501 DUK_ASSERT(i >= 0 && i < field_bytelen);
24502 p[i] = (duk_uint8_t) (tmp & 0xff);
24503 tmp = tmp >> 8; /* unnecessary shift for last byte */
24504 } while (i != i_end);
24505#else
24506 tmp = duk_to_number(ctx, 0);
24507 p = (duk_uint8_t *) (buf + offset);
24508 do {
24509 i += i_step;
24510 tmp = DUK_FLOOR(tmp);
24511 DUK_ASSERT(i >= 0 && i < field_bytelen);
24512 p[i] = (duk_uint8_t) (DUK_FMOD(tmp, 256.0));
24513 tmp = tmp / 256.0; /* unnecessary div for last byte */
24514 } while (i != i_end);
24515#endif
24516 break;
24517 }
24518 default: { /* should never happen but default here */
24519 goto fail_bounds;
24520 }
24521 }
24522
24523 /* Node.js Buffer: return offset + #bytes written (i.e. next
24524 * write offset).
24525 */
24526 if (magic_typedarray) {
24527 /* For TypedArrays 'undefined' return value is specified
24528 * by ES6 (matches V8).
24529 */
24530 return 0;
24531 }
24532 duk_push_uint(ctx, offset + nbytes);
24533 return 1;
24534
11fdf7f2 24535 fail_neutered:
7c673cae
FG
24536 fail_field_length:
24537 fail_bounds:
24538 if (no_assert) {
24539 /* Node.js return value for failed writes is offset + #bytes
24540 * that would have been written.
24541 */
24542 /* XXX: for negative input offsets, 'offset' will be a large
24543 * positive value so the result here is confusing.
24544 */
24545 if (magic_typedarray) {
24546 return 0;
24547 }
24548 duk_push_uint(ctx, offset + nbytes);
24549 return 1;
24550 }
24551 return DUK_RET_RANGE_ERROR;
24552}
24553#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
24554DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
24555 DUK_UNREF(ctx);
24556 return DUK_RET_UNSUPPORTED_ERROR;
24557}
24558#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
24559
24560#undef DUK__FLD_8BIT
24561#undef DUK__FLD_16BIT
24562#undef DUK__FLD_32BIT
24563#undef DUK__FLD_FLOAT
24564#undef DUK__FLD_DOUBLE
24565#undef DUK__FLD_VARINT
24566#undef DUK__FLD_BIGENDIAN
24567#undef DUK__FLD_SIGNED
24568#undef DUK__FLD_TYPEDARRAY
7c673cae
FG
24569/*
24570 * Date built-ins
24571 *
24572 * Unlike most built-ins, Date has some platform dependencies for getting
24573 * UTC time, converting between UTC and local time, and parsing and
24574 * formatting time values. These are all abstracted behind DUK_USE_xxx
24575 * config options. There are built-in platform specific providers for
24576 * POSIX and Windows, but external providers can also be used.
24577 *
24578 * See doc/datetime.rst.
24579 *
24580 */
24581
24582/* include removed: duk_internal.h */
24583
24584/*
24585 * Forward declarations
24586 */
24587
24588DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval_tzoffset(duk_context *ctx, duk_small_uint_t flags, duk_int_t *out_tzoffset);
24589DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval(duk_context *ctx, duk_small_uint_t flags);
24590DUK_LOCAL_DECL void duk__twodigit_year_fixup(duk_context *ctx, duk_idx_t idx_val);
24591DUK_LOCAL_DECL duk_ret_t duk__set_this_timeval_from_dparts(duk_context *ctx, duk_double_t *dparts, duk_small_uint_t flags);
24592
24593/*
24594 * Other file level defines
24595 */
24596
24597/* Debug macro to print all parts and dparts (used manually because of debug level). */
24598#define DUK__DPRINT_PARTS_AND_DPARTS(parts,dparts) do { \
24599 DUK_D(DUK_DPRINT("parts: %ld %ld %ld %ld %ld %ld %ld %ld, dparts: %lf %lf %lf %lf %lf %lf %lf %lf", \
24600 (long) (parts)[0], (long) (parts)[1], \
24601 (long) (parts)[2], (long) (parts)[3], \
24602 (long) (parts)[4], (long) (parts)[5], \
24603 (long) (parts)[6], (long) (parts)[7], \
24604 (double) (dparts)[0], (double) (dparts)[1], \
24605 (double) (dparts)[2], (double) (dparts)[3], \
24606 (double) (dparts)[4], (double) (dparts)[5], \
24607 (double) (dparts)[6], (double) (dparts)[7])); \
24608 } while (0)
24609#define DUK__DPRINT_PARTS(parts) do { \
24610 DUK_D(DUK_DPRINT("parts: %ld %ld %ld %ld %ld %ld %ld %ld", \
24611 (long) (parts)[0], (long) (parts)[1], \
24612 (long) (parts)[2], (long) (parts)[3], \
24613 (long) (parts)[4], (long) (parts)[5], \
24614 (long) (parts)[6], (long) (parts)[7])); \
24615 } while (0)
24616#define DUK__DPRINT_DPARTS(dparts) do { \
24617 DUK_D(DUK_DPRINT("dparts: %lf %lf %lf %lf %lf %lf %lf %lf", \
24618 (double) (dparts)[0], (double) (dparts)[1], \
24619 (double) (dparts)[2], (double) (dparts)[3], \
24620 (double) (dparts)[4], (double) (dparts)[5], \
24621 (double) (dparts)[6], (double) (dparts)[7])); \
24622 } while (0)
24623
24624/* Equivalent year for DST calculations outside [1970,2038[ range, see
24625 * E5 Section 15.9.1.8. Equivalent year has the same leap-year-ness and
24626 * starts with the same weekday on Jan 1.
24627 * https://bugzilla.mozilla.org/show_bug.cgi?id=351066
24628 */
24629#define DUK__YEAR(x) ((duk_uint8_t) ((x) - 1970))
24630DUK_LOCAL duk_uint8_t duk__date_equivyear[14] = {
24631#if 1
24632 /* This is based on V8 EquivalentYear() algorithm (see src/genequivyear.py):
24633 * http://code.google.com/p/v8/source/browse/trunk/src/date.h#146
24634 */
24635
24636 /* non-leap year: sunday, monday, ... */
24637 DUK__YEAR(2023), DUK__YEAR(2035), DUK__YEAR(2019), DUK__YEAR(2031),
24638 DUK__YEAR(2015), DUK__YEAR(2027), DUK__YEAR(2011),
24639
24640 /* leap year: sunday, monday, ... */
24641 DUK__YEAR(2012), DUK__YEAR(2024), DUK__YEAR(2008), DUK__YEAR(2020),
24642 DUK__YEAR(2032), DUK__YEAR(2016), DUK__YEAR(2028)
24643#endif
24644
24645#if 0
24646 /* This is based on Rhino EquivalentYear() algorithm:
24647 * https://github.com/mozilla/rhino/blob/f99cc11d616f0cdda2c42bde72b3484df6182947/src/org/mozilla/javascript/NativeDate.java
24648 */
24649
24650 /* non-leap year: sunday, monday, ... */
24651 DUK__YEAR(1978), DUK__YEAR(1973), DUK__YEAR(1985), DUK__YEAR(1986),
24652 DUK__YEAR(1981), DUK__YEAR(1971), DUK__YEAR(1977),
24653
24654 /* leap year: sunday, monday, ... */
24655 DUK__YEAR(1984), DUK__YEAR(1996), DUK__YEAR(1980), DUK__YEAR(1992),
24656 DUK__YEAR(1976), DUK__YEAR(1988), DUK__YEAR(1972)
24657#endif
24658};
24659#undef DUK__YEAR
24660
24661/*
24662 * ISO 8601 subset parser.
24663 */
24664
24665/* Parser part count. */
24666#define DUK__NUM_ISO8601_PARSER_PARTS 9
24667
24668/* Parser part indices. */
24669#define DUK__PI_YEAR 0
24670#define DUK__PI_MONTH 1
24671#define DUK__PI_DAY 2
24672#define DUK__PI_HOUR 3
24673#define DUK__PI_MINUTE 4
24674#define DUK__PI_SECOND 5
24675#define DUK__PI_MILLISECOND 6
24676#define DUK__PI_TZHOUR 7
24677#define DUK__PI_TZMINUTE 8
24678
24679/* Parser part masks. */
24680#define DUK__PM_YEAR (1 << DUK__PI_YEAR)
24681#define DUK__PM_MONTH (1 << DUK__PI_MONTH)
24682#define DUK__PM_DAY (1 << DUK__PI_DAY)
24683#define DUK__PM_HOUR (1 << DUK__PI_HOUR)
24684#define DUK__PM_MINUTE (1 << DUK__PI_MINUTE)
24685#define DUK__PM_SECOND (1 << DUK__PI_SECOND)
24686#define DUK__PM_MILLISECOND (1 << DUK__PI_MILLISECOND)
24687#define DUK__PM_TZHOUR (1 << DUK__PI_TZHOUR)
24688#define DUK__PM_TZMINUTE (1 << DUK__PI_TZMINUTE)
24689
24690/* Parser separator indices. */
24691#define DUK__SI_PLUS 0
24692#define DUK__SI_MINUS 1
24693#define DUK__SI_T 2
24694#define DUK__SI_SPACE 3
24695#define DUK__SI_COLON 4
24696#define DUK__SI_PERIOD 5
24697#define DUK__SI_Z 6
24698#define DUK__SI_NUL 7
24699
24700/* Parser separator masks. */
24701#define DUK__SM_PLUS (1 << DUK__SI_PLUS)
24702#define DUK__SM_MINUS (1 << DUK__SI_MINUS)
24703#define DUK__SM_T (1 << DUK__SI_T)
24704#define DUK__SM_SPACE (1 << DUK__SI_SPACE)
24705#define DUK__SM_COLON (1 << DUK__SI_COLON)
24706#define DUK__SM_PERIOD (1 << DUK__SI_PERIOD)
24707#define DUK__SM_Z (1 << DUK__SI_Z)
24708#define DUK__SM_NUL (1 << DUK__SI_NUL)
24709
24710/* Rule control flags. */
24711#define DUK__CF_NEG (1 << 0) /* continue matching, set neg_tzoffset flag */
24712#define DUK__CF_ACCEPT (1 << 1) /* accept string */
24713#define DUK__CF_ACCEPT_NUL (1 << 2) /* accept string if next char is NUL (otherwise reject) */
24714
24715#define DUK__PACK_RULE(partmask,sepmask,nextpart,flags) \
24716 ((duk_uint32_t) (partmask) + \
24717 (((duk_uint32_t) (sepmask)) << 9) + \
24718 (((duk_uint32_t) (nextpart)) << 17) + \
24719 (((duk_uint32_t) (flags)) << 21))
24720
24721#define DUK__UNPACK_RULE(rule,var_nextidx,var_flags) do { \
24722 (var_nextidx) = (duk_small_uint_t) (((rule) >> 17) & 0x0f); \
24723 (var_flags) = (duk_small_uint_t) ((rule) >> 21); \
24724 } while (0)
24725
24726#define DUK__RULE_MASK_PART_SEP 0x1ffffUL
24727
24728/* Matching separator index is used in the control table */
24729DUK_LOCAL const duk_uint8_t duk__parse_iso8601_seps[] = {
24730 DUK_ASC_PLUS /*0*/, DUK_ASC_MINUS /*1*/, DUK_ASC_UC_T /*2*/, DUK_ASC_SPACE /*3*/,
24731 DUK_ASC_COLON /*4*/, DUK_ASC_PERIOD /*5*/, DUK_ASC_UC_Z /*6*/, DUK_ASC_NUL /*7*/
24732};
24733
24734/* Rule table: first matching rule is used to determine what to do next. */
24735DUK_LOCAL const duk_uint32_t duk__parse_iso8601_control[] = {
24736 DUK__PACK_RULE(DUK__PM_YEAR, DUK__SM_MINUS, DUK__PI_MONTH, 0),
24737 DUK__PACK_RULE(DUK__PM_MONTH, DUK__SM_MINUS, DUK__PI_DAY, 0),
24738 DUK__PACK_RULE(DUK__PM_YEAR | DUK__PM_MONTH | DUK__PM_DAY, DUK__SM_T | DUK__SM_SPACE, DUK__PI_HOUR, 0),
24739 DUK__PACK_RULE(DUK__PM_HOUR, DUK__SM_COLON, DUK__PI_MINUTE, 0),
24740 DUK__PACK_RULE(DUK__PM_MINUTE, DUK__SM_COLON, DUK__PI_SECOND, 0),
24741 DUK__PACK_RULE(DUK__PM_SECOND, DUK__SM_PERIOD, DUK__PI_MILLISECOND, 0),
24742 DUK__PACK_RULE(DUK__PM_TZHOUR, DUK__SM_COLON, DUK__PI_TZMINUTE, 0),
24743 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),
24744 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),
24745 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),
24746 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)
24747
24748 /* Note1: the specification doesn't require matching a time form with
24749 * just hours ("HH"), but we accept it here, e.g. "2012-01-02T12Z".
24750 *
24751 * Note2: the specification doesn't require matching a timezone offset
24752 * with just hours ("HH"), but accept it here, e.g. "2012-01-02T03:04:05+02"
24753 */
24754};
24755
24756DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_context *ctx, const char *str) {
24757 duk_int_t parts[DUK__NUM_ISO8601_PARSER_PARTS];
24758 duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
24759 duk_double_t d;
24760 const duk_uint8_t *p;
24761 duk_small_uint_t part_idx = 0;
24762 duk_int_t accum = 0;
24763 duk_small_uint_t ndigits = 0;
24764 duk_bool_t neg_year = 0;
24765 duk_bool_t neg_tzoffset = 0;
24766 duk_uint_fast8_t ch;
24767 duk_small_uint_t i;
24768
24769 /* During parsing, month and day are one-based; set defaults here. */
24770 DUK_MEMZERO(parts, sizeof(parts));
24771 DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] == 0); /* don't care value, year is mandatory */
24772 parts[DUK_DATE_IDX_MONTH] = 1;
24773 parts[DUK_DATE_IDX_DAY] = 1;
24774
24775 /* Special handling for year sign. */
24776 p = (const duk_uint8_t *) str;
24777 ch = p[0];
24778 if (ch == DUK_ASC_PLUS) {
24779 p++;
24780 } else if (ch == DUK_ASC_MINUS) {
24781 neg_year = 1;
24782 p++;
24783 }
24784
24785 for (;;) {
24786 ch = *p++;
24787 DUK_DDD(DUK_DDDPRINT("parsing, part_idx=%ld, char=%ld ('%c')",
24788 (long) part_idx, (long) ch,
24789 (int) ((ch >= 0x20 && ch <= 0x7e) ? ch : DUK_ASC_QUESTION)));
24790
24791 if (ch >= DUK_ASC_0 && ch <= DUK_ASC_9) {
24792 if (ndigits >= 9) {
24793 DUK_DDD(DUK_DDDPRINT("too many digits -> reject"));
24794 goto reject;
24795 }
24796 if (part_idx == DUK__PI_MILLISECOND /*msec*/ && ndigits >= 3) {
24797 /* ignore millisecond fractions after 3 */
24798 } else {
24799 accum = accum * 10 + ((duk_int_t) ch) - ((duk_int_t) DUK_ASC_0) + 0x00;
24800 ndigits++;
24801 }
24802 } else {
24803 duk_uint_fast32_t match_val;
24804 duk_small_int_t sep_idx;
24805
24806 if (ndigits <= 0) {
24807 goto reject;
24808 }
24809 if (part_idx == DUK__PI_MILLISECOND) {
24810 /* complete the millisecond field */
24811 while (ndigits < 3) {
24812 accum *= 10;
24813 ndigits++;
24814 }
24815 }
24816 parts[part_idx] = accum;
24817 DUK_DDD(DUK_DDDPRINT("wrote part %ld -> value %ld", (long) part_idx, (long) accum));
24818
24819 accum = 0;
24820 ndigits = 0;
24821
24822 for (i = 0; i < (duk_small_uint_t) (sizeof(duk__parse_iso8601_seps) / sizeof(duk_uint8_t)); i++) {
24823 if (duk__parse_iso8601_seps[i] == ch) {
24824 break;
24825 }
24826 }
24827 if (i == (duk_small_uint_t) (sizeof(duk__parse_iso8601_seps) / sizeof(duk_uint8_t))) {
24828 DUK_DDD(DUK_DDDPRINT("separator character doesn't match -> reject"));
24829 goto reject;
24830 }
24831
24832 sep_idx = i;
24833 match_val = (1UL << part_idx) + (1UL << (sep_idx + 9)); /* match against rule part/sep bits */
24834
24835 for (i = 0; i < (duk_small_uint_t) (sizeof(duk__parse_iso8601_control) / sizeof(duk_uint32_t)); i++) {
24836 duk_uint_fast32_t rule = duk__parse_iso8601_control[i];
24837 duk_small_uint_t nextpart;
24838 duk_small_uint_t cflags;
24839
24840 DUK_DDD(DUK_DDDPRINT("part_idx=%ld, sep_idx=%ld, match_val=0x%08lx, considering rule=0x%08lx",
24841 (long) part_idx, (long) sep_idx,
24842 (unsigned long) match_val, (unsigned long) rule));
24843
24844 if ((rule & match_val) != match_val) {
24845 continue;
24846 }
24847
24848 DUK__UNPACK_RULE(rule, nextpart, cflags);
24849
24850 DUK_DDD(DUK_DDDPRINT("rule match -> part_idx=%ld, sep_idx=%ld, match_val=0x%08lx, "
24851 "rule=0x%08lx -> nextpart=%ld, cflags=0x%02lx",
24852 (long) part_idx, (long) sep_idx,
24853 (unsigned long) match_val, (unsigned long) rule,
24854 (long) nextpart, (unsigned long) cflags));
24855
24856 if (cflags & DUK__CF_NEG) {
24857 neg_tzoffset = 1;
24858 }
24859
24860 if (cflags & DUK__CF_ACCEPT) {
24861 goto accept;
24862 }
24863
24864 if (cflags & DUK__CF_ACCEPT_NUL) {
24865 DUK_ASSERT(*(p - 1) != (char) 0);
24866 if (*p == DUK_ASC_NUL) {
24867 goto accept;
24868 }
24869 goto reject;
24870 }
24871
24872 part_idx = nextpart;
24873 break;
24874 } /* rule match */
24875
24876 if (i == (duk_small_uint_t) (sizeof(duk__parse_iso8601_control) / sizeof(duk_uint32_t))) {
24877 DUK_DDD(DUK_DDDPRINT("no rule matches -> reject"));
24878 goto reject;
24879 }
24880
24881 if (ch == 0) {
24882 /* This shouldn't be necessary, but check just in case
24883 * to avoid any chance of overruns.
24884 */
24885 DUK_DDD(DUK_DDDPRINT("NUL after rule matching (should not happen) -> reject"));
24886 goto reject;
24887 }
24888 } /* if-digit-else-ctrl */
24889 } /* char loop */
24890
11fdf7f2
TL
24891 /* We should never exit the loop above. */
24892 DUK_UNREACHABLE();
7c673cae
FG
24893
24894 reject:
24895 DUK_DDD(DUK_DDDPRINT("reject"));
24896 return 0;
24897
24898 accept:
24899 DUK_DDD(DUK_DDDPRINT("accept"));
24900
24901 /* Apply timezone offset to get the main parts in UTC */
24902 if (neg_year) {
24903 parts[DUK__PI_YEAR] = -parts[DUK__PI_YEAR];
24904 }
24905 if (neg_tzoffset) {
24906 parts[DUK__PI_HOUR] += parts[DUK__PI_TZHOUR];
24907 parts[DUK__PI_MINUTE] += parts[DUK__PI_TZMINUTE];
24908 } else {
24909 parts[DUK__PI_HOUR] -= parts[DUK__PI_TZHOUR];
24910 parts[DUK__PI_MINUTE] -= parts[DUK__PI_TZMINUTE];
24911 }
24912 parts[DUK__PI_MONTH] -= 1; /* zero-based month */
24913 parts[DUK__PI_DAY] -= 1; /* zero-based day */
24914
24915 /* Use double parts, they tolerate unnormalized time.
24916 *
24917 * Note: DUK_DATE_IDX_WEEKDAY is initialized with a bogus value (DUK__PI_TZHOUR)
24918 * on purpose. It won't be actually used by duk_bi_date_get_timeval_from_dparts(),
24919 * but will make the value initialized just in case, and avoid any
24920 * potential for Valgrind issues.
24921 */
24922 for (i = 0; i < DUK_DATE_IDX_NUM_PARTS; i++) {
24923 DUK_DDD(DUK_DDDPRINT("part[%ld] = %ld", (long) i, (long) parts[i]));
24924 dparts[i] = parts[i];
24925 }
24926
24927 d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/);
24928 duk_push_number(ctx, d);
24929 return 1;
24930}
24931
24932/*
24933 * Date/time parsing helper.
24934 *
24935 * Parse a datetime string into a time value. We must first try to parse
24936 * the input according to the standard format in E5.1 Section 15.9.1.15.
24937 * If that fails, we can try to parse using custom parsing, which can
24938 * either be platform neutral (custom code) or platform specific (using
24939 * existing platform API calls).
24940 *
24941 * Note in particular that we must parse whatever toString(), toUTCString(),
24942 * and toISOString() can produce; see E5.1 Section 15.9.4.2.
24943 *
24944 * Returns 1 to allow tail calling.
24945 *
24946 * There is much room for improvement here with respect to supporting
24947 * alternative datetime formats. For instance, V8 parses '2012-01-01' as
24948 * UTC and '2012/01/01' as local time.
24949 */
24950
24951DUK_LOCAL duk_ret_t duk__parse_string(duk_context *ctx, const char *str) {
24952 /* XXX: there is a small risk here: because the ISO 8601 parser is
24953 * very loose, it may end up parsing some datetime values which
24954 * would be better parsed with a platform specific parser.
24955 */
24956
24957 DUK_ASSERT(str != NULL);
24958 DUK_DDD(DUK_DDDPRINT("parse datetime from string '%s'", (const char *) str));
24959
24960 if (duk__parse_string_iso8601_subset(ctx, str) != 0) {
24961 return 1;
24962 }
24963
24964#if defined(DUK_USE_DATE_PARSE_STRING)
24965 /* Contract, either:
24966 * - Push value on stack and return 1
24967 * - Don't push anything on stack and return 0
24968 */
24969
24970 if (DUK_USE_DATE_PARSE_STRING(ctx, str) != 0) {
24971 return 1;
24972 }
24973#else
24974 /* No platform-specific parsing, this is not an error. */
24975#endif
24976
24977 duk_push_nan(ctx);
24978 return 1;
24979}
24980
24981/*
24982 * Calendar helpers
24983 *
24984 * Some helpers are used for getters and can operate on normalized values
24985 * which can be represented with 32-bit signed integers. Other helpers are
24986 * needed by setters and operate on un-normalized double values, must watch
24987 * out for non-finite numbers etc.
24988 */
24989
24990DUK_LOCAL duk_uint8_t duk__days_in_month[12] = {
24991 (duk_uint8_t) 31, (duk_uint8_t) 28, (duk_uint8_t) 31, (duk_uint8_t) 30,
24992 (duk_uint8_t) 31, (duk_uint8_t) 30, (duk_uint8_t) 31, (duk_uint8_t) 31,
24993 (duk_uint8_t) 30, (duk_uint8_t) 31, (duk_uint8_t) 30, (duk_uint8_t) 31
24994};
24995
24996/* Maximum iteration count for computing UTC-to-local time offset when
24997 * creating an Ecmascript time value from local parts.
24998 */
24999#define DUK__LOCAL_TZOFFSET_MAXITER 4
25000
25001/* Because 'day since epoch' can be negative and is used to compute weekday
25002 * using a modulo operation, add this multiple of 7 to avoid negative values
25003 * when year is below 1970 epoch. Ecmascript time values are restricted to
25004 * +/- 100 million days from epoch, so this adder fits nicely into 32 bits.
25005 * Round to a multiple of 7 (= floor(100000000 / 7) * 7) and add margin.
25006 */
25007#define DUK__WEEKDAY_MOD_ADDER (20000000 * 7) /* 0x08583b00 */
25008
25009DUK_INTERNAL duk_bool_t duk_bi_date_is_leap_year(duk_int_t year) {
25010 if ((year % 4) != 0) {
25011 return 0;
25012 }
25013 if ((year % 100) != 0) {
25014 return 1;
25015 }
25016 if ((year % 400) != 0) {
25017 return 0;
25018 }
25019 return 1;
25020}
25021
25022DUK_INTERNAL duk_bool_t duk_bi_date_timeval_in_valid_range(duk_double_t x) {
25023 return (x >= -DUK_DATE_MSEC_100M_DAYS && x <= DUK_DATE_MSEC_100M_DAYS);
25024}
25025
25026DUK_INTERNAL duk_bool_t duk_bi_date_timeval_in_leeway_range(duk_double_t x) {
25027 return (x >= -DUK_DATE_MSEC_100M_DAYS_LEEWAY && x <= DUK_DATE_MSEC_100M_DAYS_LEEWAY);
25028}
25029
25030DUK_INTERNAL duk_bool_t duk_bi_date_year_in_valid_range(duk_double_t x) {
25031 return (x >= DUK_DATE_MIN_ECMA_YEAR && x <= DUK_DATE_MAX_ECMA_YEAR);
25032}
25033
25034DUK_LOCAL duk_double_t duk__timeclip(duk_double_t x) {
25035 if (!DUK_ISFINITE(x)) {
25036 return DUK_DOUBLE_NAN;
25037 }
25038
25039 if (!duk_bi_date_timeval_in_valid_range(x)) {
25040 return DUK_DOUBLE_NAN;
25041 }
25042
25043 x = duk_js_tointeger_number(x);
25044
25045 /* Here we'd have the option to normalize -0 to +0. */
25046 return x;
25047}
25048
25049/* Integer division which floors also negative values correctly. */
25050DUK_LOCAL duk_int_t duk__div_floor(duk_int_t a, duk_int_t b) {
25051 DUK_ASSERT(b > 0);
25052 if (a >= 0) {
25053 return a / b;
25054 } else {
25055 /* e.g. a = -4, b = 5 --> -4 - 5 + 1 / 5 --> -8 / 5 --> -1
25056 * a = -5, b = 5 --> -5 - 5 + 1 / 5 --> -9 / 5 --> -1
25057 * a = -6, b = 5 --> -6 - 5 + 1 / 5 --> -10 / 5 --> -2
25058 */
25059 return (a - b + 1) / b;
25060 }
25061}
25062
25063/* Compute day number of the first day of a given year. */
25064DUK_LOCAL duk_int_t duk__day_from_year(duk_int_t year) {
25065 /* Note: in integer arithmetic, (x / 4) is same as floor(x / 4) for non-negative
25066 * values, but is incorrect for negative ones.
25067 */
25068 return 365 * (year - 1970)
25069 + duk__div_floor(year - 1969, 4)
25070 - duk__div_floor(year - 1901, 100)
25071 + duk__div_floor(year - 1601, 400);
25072}
25073
25074/* Given a day number, determine year and day-within-year. */
25075DUK_LOCAL duk_int_t duk__year_from_day(duk_int_t day, duk_small_int_t *out_day_within_year) {
25076 duk_int_t year;
25077 duk_int_t diff_days;
25078
25079 /* estimate year upwards (towards positive infinity), then back down;
25080 * two iterations should be enough
25081 */
25082
25083 if (day >= 0) {
25084 year = 1970 + day / 365;
25085 } else {
25086 year = 1970 + day / 366;
25087 }
25088
25089 for (;;) {
25090 diff_days = duk__day_from_year(year) - day;
25091 DUK_DDD(DUK_DDDPRINT("year=%ld day=%ld, diff_days=%ld", (long) year, (long) day, (long) diff_days));
25092 if (diff_days <= 0) {
25093 DUK_ASSERT(-diff_days < 366); /* fits into duk_small_int_t */
25094 *out_day_within_year = -diff_days;
25095 DUK_DDD(DUK_DDDPRINT("--> year=%ld, day-within-year=%ld",
25096 (long) year, (long) *out_day_within_year));
25097 DUK_ASSERT(*out_day_within_year >= 0);
25098 DUK_ASSERT(*out_day_within_year < (duk_bi_date_is_leap_year(year) ? 366 : 365));
25099 return year;
25100 }
25101
25102 /* Note: this is very tricky; we must never 'overshoot' the
25103 * correction downwards.
25104 */
25105 year -= 1 + (diff_days - 1) / 366; /* conservative */
25106 }
25107}
25108
25109/* Given a (year, month, day-within-month) triple, compute day number.
25110 * The input triple is un-normalized and may contain non-finite values.
25111 */
25112DUK_LOCAL duk_double_t duk__make_day(duk_double_t year, duk_double_t month, duk_double_t day) {
25113 duk_int_t day_num;
25114 duk_bool_t is_leap;
25115 duk_small_int_t i, n;
25116
25117 /* Assume that year, month, day are all coerced to whole numbers.
25118 * They may also be NaN or infinity, in which case this function
25119 * must return NaN or infinity to ensure time value becomes NaN.
25120 * If 'day' is NaN, the final return will end up returning a NaN,
25121 * so it doesn't need to be checked here.
25122 */
25123
25124 if (!DUK_ISFINITE(year) || !DUK_ISFINITE(month)) {
25125 return DUK_DOUBLE_NAN;
25126 }
25127
25128 year += DUK_FLOOR(month / 12.0);
25129
25130 month = DUK_FMOD(month, 12.0);
25131 if (month < 0.0) {
25132 /* handle negative values */
25133 month += 12.0;
25134 }
25135
25136 /* The algorithm in E5.1 Section 15.9.1.12 normalizes month, but
25137 * does not normalize the day-of-month (nor check whether or not
25138 * it is finite) because it's not necessary for finding the day
25139 * number which matches the (year,month) pair.
25140 *
25141 * We assume that duk__day_from_year() is exact here.
25142 *
25143 * Without an explicit infinity / NaN check in the beginning,
25144 * day_num would be a bogus integer here.
25145 *
25146 * It's possible for 'year' to be out of integer range here.
25147 * If so, we need to return NaN without integer overflow.
25148 * This fixes test-bug-setyear-overflow.js.
25149 */
25150
25151 if (!duk_bi_date_year_in_valid_range(year)) {
25152 DUK_DD(DUK_DDPRINT("year not in ecmascript valid range, avoid integer overflow: %lf", (double) year));
25153 return DUK_DOUBLE_NAN;
25154 }
25155 day_num = duk__day_from_year((duk_int_t) year);
25156 is_leap = duk_bi_date_is_leap_year((duk_int_t) year);
25157
25158 n = (duk_small_int_t) month;
25159 for (i = 0; i < n; i++) {
25160 day_num += duk__days_in_month[i];
25161 if (i == 1 && is_leap) {
25162 day_num++;
25163 }
25164 }
25165
25166 /* If 'day' is NaN, returns NaN. */
25167 return (duk_double_t) day_num + day;
25168}
25169
25170/* Split time value into parts. The time value is assumed to be an internal
25171 * one, i.e. finite, no fractions. Possible local time adjustment has already
25172 * been applied when reading the time value.
25173 */
25174DUK_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) {
25175 duk_double_t d1, d2;
25176 duk_int_t t1, t2;
25177 duk_int_t day_since_epoch;
25178 duk_int_t year; /* does not fit into 16 bits */
25179 duk_small_int_t day_in_year;
25180 duk_small_int_t month;
25181 duk_small_int_t day;
25182 duk_small_int_t dim;
25183 duk_int_t jan1_since_epoch;
25184 duk_small_int_t jan1_weekday;
25185 duk_int_t equiv_year;
25186 duk_small_uint_t i;
25187 duk_bool_t is_leap;
25188 duk_small_int_t arridx;
25189
25190 DUK_ASSERT(DUK_ISFINITE(d)); /* caller checks */
25191 DUK_ASSERT(DUK_FLOOR(d) == d); /* no fractions in internal time */
25192
25193 /* The timevalue must be in valid Ecmascript range, but since a local
25194 * time offset can be applied, we need to allow a +/- 24h leeway to
25195 * the value. In other words, although the UTC time is within the
25196 * Ecmascript range, the local part values can be just outside of it.
25197 */
25198 DUK_UNREF(duk_bi_date_timeval_in_leeway_range);
25199 DUK_ASSERT(duk_bi_date_timeval_in_leeway_range(d));
25200
25201 /* these computations are guaranteed to be exact for the valid
25202 * E5 time value range, assuming milliseconds without fractions.
25203 */
25204 d1 = (duk_double_t) DUK_FMOD(d, (double) DUK_DATE_MSEC_DAY);
25205 if (d1 < 0.0) {
25206 /* deal with negative values */
25207 d1 += (duk_double_t) DUK_DATE_MSEC_DAY;
25208 }
25209 d2 = DUK_FLOOR((double) (d / (duk_double_t) DUK_DATE_MSEC_DAY));
25210 DUK_ASSERT(d2 * ((duk_double_t) DUK_DATE_MSEC_DAY) + d1 == d);
25211 /* now expected to fit into a 32-bit integer */
25212 t1 = (duk_int_t) d1;
25213 t2 = (duk_int_t) d2;
25214 day_since_epoch = t2;
25215 DUK_ASSERT((duk_double_t) t1 == d1);
25216 DUK_ASSERT((duk_double_t) t2 == d2);
25217
25218 /* t1 = milliseconds within day (fits 32 bit)
25219 * t2 = day number from epoch (fits 32 bit, may be negative)
25220 */
25221
25222 parts[DUK_DATE_IDX_MILLISECOND] = t1 % 1000; t1 /= 1000;
25223 parts[DUK_DATE_IDX_SECOND] = t1 % 60; t1 /= 60;
25224 parts[DUK_DATE_IDX_MINUTE] = t1 % 60; t1 /= 60;
25225 parts[DUK_DATE_IDX_HOUR] = t1;
25226 DUK_ASSERT(parts[DUK_DATE_IDX_MILLISECOND] >= 0 && parts[DUK_DATE_IDX_MILLISECOND] <= 999);
25227 DUK_ASSERT(parts[DUK_DATE_IDX_SECOND] >= 0 && parts[DUK_DATE_IDX_SECOND] <= 59);
25228 DUK_ASSERT(parts[DUK_DATE_IDX_MINUTE] >= 0 && parts[DUK_DATE_IDX_MINUTE] <= 59);
25229 DUK_ASSERT(parts[DUK_DATE_IDX_HOUR] >= 0 && parts[DUK_DATE_IDX_HOUR] <= 23);
25230
25231 DUK_DDD(DUK_DDDPRINT("d=%lf, d1=%lf, d2=%lf, t1=%ld, t2=%ld, parts: hour=%ld min=%ld sec=%ld msec=%ld",
25232 (double) d, (double) d1, (double) d2, (long) t1, (long) t2,
25233 (long) parts[DUK_DATE_IDX_HOUR],
25234 (long) parts[DUK_DATE_IDX_MINUTE],
25235 (long) parts[DUK_DATE_IDX_SECOND],
25236 (long) parts[DUK_DATE_IDX_MILLISECOND]));
25237
25238 /* This assert depends on the input parts representing time inside
25239 * the Ecmascript range.
25240 */
25241 DUK_ASSERT(t2 + DUK__WEEKDAY_MOD_ADDER >= 0);
25242 parts[DUK_DATE_IDX_WEEKDAY] = (t2 + 4 + DUK__WEEKDAY_MOD_ADDER) % 7; /* E5.1 Section 15.9.1.6 */
25243 DUK_ASSERT(parts[DUK_DATE_IDX_WEEKDAY] >= 0 && parts[DUK_DATE_IDX_WEEKDAY] <= 6);
25244
25245 year = duk__year_from_day(t2, &day_in_year);
25246 day = day_in_year;
25247 is_leap = duk_bi_date_is_leap_year(year);
25248 for (month = 0; month < 12; month++) {
25249 dim = duk__days_in_month[month];
25250 if (month == 1 && is_leap) {
25251 dim++;
25252 }
25253 DUK_DDD(DUK_DDDPRINT("month=%ld, dim=%ld, day=%ld",
25254 (long) month, (long) dim, (long) day));
25255 if (day < dim) {
25256 break;
25257 }
25258 day -= dim;
25259 }
25260 DUK_DDD(DUK_DDDPRINT("final month=%ld", (long) month));
25261 DUK_ASSERT(month >= 0 && month <= 11);
25262 DUK_ASSERT(day >= 0 && day <= 31);
25263
25264 /* Equivalent year mapping, used to avoid DST trouble when platform
25265 * may fail to provide reasonable DST answers for dates outside the
25266 * ordinary range (e.g. 1970-2038). An equivalent year has the same
25267 * leap-year-ness as the original year and begins on the same weekday
25268 * (Jan 1).
25269 *
25270 * The year 2038 is avoided because there seem to be problems with it
25271 * on some platforms. The year 1970 is also avoided as there were
25272 * practical problems with it; an equivalent year is used for it too,
25273 * which breaks some DST computations for 1970 right now, see e.g.
25274 * test-bi-date-tzoffset-brute-fi.js.
25275 */
25276 if ((flags & DUK_DATE_FLAG_EQUIVYEAR) && (year < 1971 || year > 2037)) {
25277 DUK_ASSERT(is_leap == 0 || is_leap == 1);
25278
25279 jan1_since_epoch = day_since_epoch - day_in_year; /* day number for Jan 1 since epoch */
25280 DUK_ASSERT(jan1_since_epoch + DUK__WEEKDAY_MOD_ADDER >= 0);
25281 jan1_weekday = (jan1_since_epoch + 4 + DUK__WEEKDAY_MOD_ADDER) % 7; /* E5.1 Section 15.9.1.6 */
25282 DUK_ASSERT(jan1_weekday >= 0 && jan1_weekday <= 6);
25283 arridx = jan1_weekday;
25284 if (is_leap) {
25285 arridx += 7;
25286 }
25287 DUK_ASSERT(arridx >= 0 && arridx < (duk_small_int_t) (sizeof(duk__date_equivyear) / sizeof(duk_uint8_t)));
25288
25289 equiv_year = (duk_int_t) duk__date_equivyear[arridx] + 1970;
25290 year = equiv_year;
25291 DUK_DDD(DUK_DDDPRINT("equiv year mapping, year=%ld, day_in_year=%ld, day_since_epoch=%ld, "
25292 "jan1_since_epoch=%ld, jan1_weekday=%ld -> equiv year %ld",
25293 (long) year, (long) day_in_year, (long) day_since_epoch,
25294 (long) jan1_since_epoch, (long) jan1_weekday, (long) equiv_year));
25295 }
25296
25297 parts[DUK_DATE_IDX_YEAR] = year;
25298 parts[DUK_DATE_IDX_MONTH] = month;
25299 parts[DUK_DATE_IDX_DAY] = day;
25300
25301 if (flags & DUK_DATE_FLAG_ONEBASED) {
25302 parts[DUK_DATE_IDX_MONTH]++; /* zero-based -> one-based */
25303 parts[DUK_DATE_IDX_DAY]++; /* -""- */
25304 }
25305
25306 if (dparts != NULL) {
25307 for (i = 0; i < DUK_DATE_IDX_NUM_PARTS; i++) {
25308 dparts[i] = (duk_double_t) parts[i];
25309 }
25310 }
25311}
25312
25313/* Compute time value from (double) parts. The parts can be either UTC
25314 * or local time; if local, they need to be (conceptually) converted into
25315 * UTC time. The parts may represent valid or invalid time, and may be
25316 * wildly out of range (but may cancel each other and still come out in
25317 * the valid Date range).
25318 */
25319DUK_INTERNAL duk_double_t duk_bi_date_get_timeval_from_dparts(duk_double_t *dparts, duk_small_uint_t flags) {
25320#if defined(DUK_USE_PARANOID_DATE_COMPUTATION)
25321 /* See comments below on MakeTime why these are volatile. */
25322 volatile duk_double_t tmp_time;
25323 volatile duk_double_t tmp_day;
25324 volatile duk_double_t d;
25325#else
25326 duk_double_t tmp_time;
25327 duk_double_t tmp_day;
25328 duk_double_t d;
25329#endif
25330 duk_small_uint_t i;
25331 duk_int_t tzoff, tzoffprev1, tzoffprev2;
25332
25333 /* Expects 'this' at top of stack on entry. */
25334
25335 /* Coerce all finite parts with ToInteger(). ToInteger() must not
25336 * be called for NaN/Infinity because it will convert e.g. NaN to
25337 * zero. If ToInteger() has already been called, this has no side
25338 * effects and is idempotent.
25339 *
25340 * Don't read dparts[DUK_DATE_IDX_WEEKDAY]; it will cause Valgrind
25341 * issues if the value is uninitialized.
25342 */
25343 for (i = 0; i <= DUK_DATE_IDX_MILLISECOND; i++) {
25344 /* SCANBUILD: scan-build complains here about assigned value
25345 * being garbage or undefined. This is correct but operating
25346 * on undefined values has no ill effect and is ignored by the
25347 * caller in the case where this happens.
25348 */
25349 d = dparts[i];
25350 if (DUK_ISFINITE(d)) {
25351 dparts[i] = duk_js_tointeger_number(d);
25352 }
25353 }
25354
25355 /* Use explicit steps in computation to try to ensure that
25356 * computation happens with intermediate results coerced to
25357 * double values (instead of using something more accurate).
25358 * E.g. E5.1 Section 15.9.1.11 requires use of IEEE 754
25359 * rules (= Ecmascript '+' and '*' operators).
25360 *
25361 * Without 'volatile' even this approach fails on some platform
25362 * and compiler combinations. For instance, gcc 4.8.1 on Ubuntu
25363 * 64-bit, with -m32 and without -std=c99, test-bi-date-canceling.js
25364 * would fail because of some optimizations when computing tmp_time
25365 * (MakeTime below). Adding 'volatile' to tmp_time solved this
25366 * particular problem (annoyingly, also adding debug prints or
25367 * running the executable under valgrind hides it).
25368 */
25369
25370 /* MakeTime */
25371 tmp_time = 0.0;
25372 tmp_time += dparts[DUK_DATE_IDX_HOUR] * ((duk_double_t) DUK_DATE_MSEC_HOUR);
25373 tmp_time += dparts[DUK_DATE_IDX_MINUTE] * ((duk_double_t) DUK_DATE_MSEC_MINUTE);
25374 tmp_time += dparts[DUK_DATE_IDX_SECOND] * ((duk_double_t) DUK_DATE_MSEC_SECOND);
25375 tmp_time += dparts[DUK_DATE_IDX_MILLISECOND];
25376
25377 /* MakeDay */
25378 tmp_day = duk__make_day(dparts[DUK_DATE_IDX_YEAR], dparts[DUK_DATE_IDX_MONTH], dparts[DUK_DATE_IDX_DAY]);
25379
25380 /* MakeDate */
25381 d = tmp_day * ((duk_double_t) DUK_DATE_MSEC_DAY) + tmp_time;
25382
25383 DUK_DDD(DUK_DDDPRINT("time=%lf day=%lf --> timeval=%lf",
25384 (double) tmp_time, (double) tmp_day, (double) d));
25385
25386 /* Optional UTC conversion. */
25387 if (flags & DUK_DATE_FLAG_LOCALTIME) {
25388 /* DUK_USE_DATE_GET_LOCAL_TZOFFSET() needs to be called with a
25389 * time value computed from UTC parts. At this point we only
25390 * have 'd' which is a time value computed from local parts, so
25391 * it is off by the UTC-to-local time offset which we don't know
25392 * yet. The current solution for computing the UTC-to-local
25393 * time offset is to iterate a few times and detect a fixed
25394 * point or a two-cycle loop (or a sanity iteration limit),
25395 * see test-bi-date-local-parts.js and test-bi-date-tzoffset-basic-fi.js.
25396 *
25397 * E5.1 Section 15.9.1.9:
25398 * UTC(t) = t - LocalTZA - DaylightSavingTA(t - LocalTZA)
25399 *
25400 * For NaN/inf, DUK_USE_DATE_GET_LOCAL_TZOFFSET() returns 0.
25401 */
25402
25403#if 0
25404 /* Old solution: don't iterate, incorrect */
25405 tzoff = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d);
25406 DUK_DDD(DUK_DDDPRINT("tzoffset w/o iteration, tzoff=%ld", (long) tzoff));
25407 d -= tzoff * 1000L;
25408 DUK_UNREF(tzoffprev1);
25409 DUK_UNREF(tzoffprev2);
25410#endif
25411
25412 /* Iteration solution */
25413 tzoff = 0;
25414 tzoffprev1 = 999999999L; /* invalid value which never matches */
25415 for (i = 0; i < DUK__LOCAL_TZOFFSET_MAXITER; i++) {
25416 tzoffprev2 = tzoffprev1;
25417 tzoffprev1 = tzoff;
25418 tzoff = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d - tzoff * 1000L);
25419 DUK_DDD(DUK_DDDPRINT("tzoffset iteration, i=%d, tzoff=%ld, tzoffprev1=%ld tzoffprev2=%ld",
25420 (int) i, (long) tzoff, (long) tzoffprev1, (long) tzoffprev2));
25421 if (tzoff == tzoffprev1) {
25422 DUK_DDD(DUK_DDDPRINT("tzoffset iteration finished, i=%d, tzoff=%ld, tzoffprev1=%ld, tzoffprev2=%ld",
25423 (int) i, (long) tzoff, (long) tzoffprev1, (long) tzoffprev2));
25424 break;
25425 } else if (tzoff == tzoffprev2) {
25426 /* Two value cycle, see e.g. test-bi-date-tzoffset-basic-fi.js.
25427 * In these cases, favor a higher tzoffset to get a consistent
25428 * result which is independent of iteration count. Not sure if
25429 * this is a generically correct solution.
25430 */
25431 DUK_DDD(DUK_DDDPRINT("tzoffset iteration two-value cycle, i=%d, tzoff=%ld, tzoffprev1=%ld, tzoffprev2=%ld",
25432 (int) i, (long) tzoff, (long) tzoffprev1, (long) tzoffprev2));
25433 if (tzoffprev1 > tzoff) {
25434 tzoff = tzoffprev1;
25435 }
25436 break;
25437 }
25438 }
25439 DUK_DDD(DUK_DDDPRINT("tzoffset iteration, tzoff=%ld", (long) tzoff));
25440 d -= tzoff * 1000L;
25441 }
25442
25443 /* TimeClip(), which also handles Infinity -> NaN conversion */
25444 d = duk__timeclip(d);
25445
25446 return d;
25447}
25448
25449/*
25450 * API oriented helpers
25451 */
25452
25453/* Push 'this' binding, check that it is a Date object; then push the
25454 * internal time value. At the end, stack is: [ ... this timeval ].
25455 * Returns the time value. Local time adjustment is done if requested.
25456 */
25457DUK_LOCAL duk_double_t duk__push_this_get_timeval_tzoffset(duk_context *ctx, duk_small_uint_t flags, duk_int_t *out_tzoffset) {
25458 duk_hthread *thr = (duk_hthread *) ctx;
25459 duk_hobject *h;
25460 duk_double_t d;
25461 duk_int_t tzoffset = 0;
25462
25463 duk_push_this(ctx);
25464 h = duk_get_hobject(ctx, -1); /* XXX: getter with class check, useful in built-ins */
25465 if (h == NULL || DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_DATE) {
11fdf7f2 25466 DUK_ERROR_TYPE(thr, "expected Date");
7c673cae
FG
25467 }
25468
25469 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
25470 d = duk_to_number(ctx, -1);
25471 duk_pop(ctx);
25472
25473 if (DUK_ISNAN(d)) {
25474 if (flags & DUK_DATE_FLAG_NAN_TO_ZERO) {
25475 d = 0.0;
25476 }
25477 if (flags & DUK_DATE_FLAG_NAN_TO_RANGE_ERROR) {
11fdf7f2 25478 DUK_ERROR_RANGE(thr, "Invalid Date");
7c673cae
FG
25479 }
25480 }
25481 /* if no NaN handling flag, may still be NaN here, but not Inf */
25482 DUK_ASSERT(!DUK_ISINF(d));
25483
25484 if (flags & DUK_DATE_FLAG_LOCALTIME) {
25485 /* Note: DST adjustment is determined using UTC time.
25486 * If 'd' is NaN, tzoffset will be 0.
25487 */
25488 tzoffset = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d); /* seconds */
25489 d += tzoffset * 1000L;
25490 }
25491 if (out_tzoffset) {
25492 *out_tzoffset = tzoffset;
25493 }
25494
25495 /* [ ... this ] */
25496 return d;
25497}
25498
25499DUK_LOCAL duk_double_t duk__push_this_get_timeval(duk_context *ctx, duk_small_uint_t flags) {
25500 return duk__push_this_get_timeval_tzoffset(ctx, flags, NULL);
25501}
25502
25503/* Set timeval to 'this' from dparts, push the new time value onto the
25504 * value stack and return 1 (caller can then tail call us). Expects
25505 * the value stack to contain 'this' on the stack top.
25506 */
25507DUK_LOCAL duk_ret_t duk__set_this_timeval_from_dparts(duk_context *ctx, duk_double_t *dparts, duk_small_uint_t flags) {
25508 duk_double_t d;
25509
25510 /* [ ... this ] */
25511
25512 d = duk_bi_date_get_timeval_from_dparts(dparts, flags);
25513 duk_push_number(ctx, d); /* -> [ ... this timeval_new ] */
25514 duk_dup_top(ctx); /* -> [ ... this timeval_new timeval_new ] */
25515 duk_put_prop_stridx(ctx, -3, DUK_STRIDX_INT_VALUE);
25516
25517 /* stack top: new time value, return 1 to allow tail calls */
25518 return 1;
25519}
25520
25521/* 'out_buf' must be at least DUK_BI_DATE_ISO8601_BUFSIZE long. */
25522DUK_LOCAL void duk__format_parts_iso8601(duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags, duk_uint8_t *out_buf) {
25523 char yearstr[8]; /* "-123456\0" */
25524 char tzstr[8]; /* "+11:22\0" */
25525 char sep = (flags & DUK_DATE_FLAG_SEP_T) ? DUK_ASC_UC_T : DUK_ASC_SPACE;
25526
25527 DUK_ASSERT(parts[DUK_DATE_IDX_MONTH] >= 1 && parts[DUK_DATE_IDX_MONTH] <= 12);
25528 DUK_ASSERT(parts[DUK_DATE_IDX_DAY] >= 1 && parts[DUK_DATE_IDX_DAY] <= 31);
25529 DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] >= -999999 && parts[DUK_DATE_IDX_YEAR] <= 999999);
25530
25531 /* Note: %06d for positive value, %07d for negative value to include
25532 * sign and 6 digits.
25533 */
25534 DUK_SNPRINTF(yearstr,
25535 sizeof(yearstr),
25536 (parts[DUK_DATE_IDX_YEAR] >= 0 && parts[DUK_DATE_IDX_YEAR] <= 9999) ? "%04ld" :
25537 ((parts[DUK_DATE_IDX_YEAR] >= 0) ? "+%06ld" : "%07ld"),
25538 (long) parts[DUK_DATE_IDX_YEAR]);
25539 yearstr[sizeof(yearstr) - 1] = (char) 0;
25540
25541 if (flags & DUK_DATE_FLAG_LOCALTIME) {
25542 /* tzoffset seconds are dropped; 16 bits suffice for
25543 * time offset in minutes
25544 */
25545 if (tzoffset >= 0) {
25546 duk_small_int_t tmp = tzoffset / 60;
25547 DUK_SNPRINTF(tzstr, sizeof(tzstr), "+%02d:%02d", (int) (tmp / 60), (int) (tmp % 60));
25548 } else {
25549 duk_small_int_t tmp = -tzoffset / 60;
25550 DUK_SNPRINTF(tzstr, sizeof(tzstr), "-%02d:%02d", (int) (tmp / 60), (int) (tmp % 60));
25551 }
25552 tzstr[sizeof(tzstr) - 1] = (char) 0;
25553 } else {
25554 tzstr[0] = DUK_ASC_UC_Z;
25555 tzstr[1] = (char) 0;
25556 }
25557
25558 /* Unlike year, the other parts fit into 16 bits so %d format
25559 * is portable.
25560 */
25561 if ((flags & DUK_DATE_FLAG_TOSTRING_DATE) && (flags & DUK_DATE_FLAG_TOSTRING_TIME)) {
25562 DUK_SPRINTF((char *) out_buf, "%s-%02d-%02d%c%02d:%02d:%02d.%03d%s",
25563 (const char *) yearstr, (int) parts[DUK_DATE_IDX_MONTH], (int) parts[DUK_DATE_IDX_DAY], (int) sep,
25564 (int) parts[DUK_DATE_IDX_HOUR], (int) parts[DUK_DATE_IDX_MINUTE],
25565 (int) parts[DUK_DATE_IDX_SECOND], (int) parts[DUK_DATE_IDX_MILLISECOND], (const char *) tzstr);
25566 } else if (flags & DUK_DATE_FLAG_TOSTRING_DATE) {
25567 DUK_SPRINTF((char *) out_buf, "%s-%02d-%02d",
25568 (const char *) yearstr, (int) parts[DUK_DATE_IDX_MONTH], (int) parts[DUK_DATE_IDX_DAY]);
25569 } else {
25570 DUK_ASSERT(flags & DUK_DATE_FLAG_TOSTRING_TIME);
25571 DUK_SPRINTF((char *) out_buf, "%02d:%02d:%02d.%03d%s",
25572 (int) parts[DUK_DATE_IDX_HOUR], (int) parts[DUK_DATE_IDX_MINUTE],
25573 (int) parts[DUK_DATE_IDX_SECOND], (int) parts[DUK_DATE_IDX_MILLISECOND],
25574 (const char *) tzstr);
25575 }
25576}
25577
25578/* Helper for string conversion calls: check 'this' binding, get the
25579 * internal time value, and format date and/or time in a few formats.
25580 * Return value allows tail calls.
25581 */
25582DUK_LOCAL duk_ret_t duk__to_string_helper(duk_context *ctx, duk_small_uint_t flags) {
25583 duk_double_t d;
25584 duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
25585 duk_int_t tzoffset; /* seconds, doesn't fit into 16 bits */
25586 duk_bool_t rc;
25587 duk_uint8_t buf[DUK_BI_DATE_ISO8601_BUFSIZE];
25588
25589 DUK_UNREF(rc); /* unreferenced with some options */
25590
25591 d = duk__push_this_get_timeval_tzoffset(ctx, flags, &tzoffset);
25592 if (DUK_ISNAN(d)) {
25593 duk_push_hstring_stridx(ctx, DUK_STRIDX_INVALID_DATE);
25594 return 1;
25595 }
25596 DUK_ASSERT(DUK_ISFINITE(d));
25597
25598 /* formatters always get one-based month/day-of-month */
25599 duk_bi_date_timeval_to_parts(d, parts, NULL, DUK_DATE_FLAG_ONEBASED);
25600 DUK_ASSERT(parts[DUK_DATE_IDX_MONTH] >= 1 && parts[DUK_DATE_IDX_MONTH] <= 12);
25601 DUK_ASSERT(parts[DUK_DATE_IDX_DAY] >= 1 && parts[DUK_DATE_IDX_DAY] <= 31);
25602
25603 if (flags & DUK_DATE_FLAG_TOSTRING_LOCALE) {
25604 /* try locale specific formatter; if it refuses to format the
25605 * string, fall back to an ISO 8601 formatted value in local
25606 * time.
25607 */
25608#if defined(DUK_USE_DATE_FORMAT_STRING)
25609 /* Contract, either:
25610 * - Push string to value stack and return 1
25611 * - Don't push anything and return 0
25612 */
25613
25614 rc = DUK_USE_DATE_FORMAT_STRING(ctx, parts, tzoffset, flags);
25615 if (rc != 0) {
25616 return 1;
25617 }
25618#else
25619 /* No locale specific formatter; this is OK, we fall back
25620 * to ISO 8601.
25621 */
25622#endif
25623 }
25624
25625 /* Different calling convention than above used because the helper
25626 * is shared.
25627 */
25628 duk__format_parts_iso8601(parts, tzoffset, flags, buf);
25629 duk_push_string(ctx, (const char *) buf);
25630 return 1;
25631}
25632
25633/* Helper for component getter calls: check 'this' binding, get the
25634 * internal time value, split it into parts (either as UTC time or
25635 * local time), push a specified component as a return value to the
25636 * value stack and return 1 (caller can then tail call us).
25637 */
25638DUK_LOCAL duk_ret_t duk__get_part_helper(duk_context *ctx, duk_small_uint_t flags_and_idx) {
25639 duk_double_t d;
25640 duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
25641 duk_small_uint_t idx_part = (duk_small_uint_t) (flags_and_idx >> DUK_DATE_FLAG_VALUE_SHIFT); /* unpack args */
25642
25643 DUK_ASSERT_DISABLE(idx_part >= 0); /* unsigned */
25644 DUK_ASSERT(idx_part < DUK_DATE_IDX_NUM_PARTS);
25645
25646 d = duk__push_this_get_timeval(ctx, flags_and_idx);
25647 if (DUK_ISNAN(d)) {
25648 duk_push_nan(ctx);
25649 return 1;
25650 }
25651 DUK_ASSERT(DUK_ISFINITE(d));
25652
25653 duk_bi_date_timeval_to_parts(d, parts, NULL, flags_and_idx); /* no need to mask idx portion */
25654
25655 /* Setter APIs detect special year numbers (0...99) and apply a +1900
25656 * only in certain cases. The legacy getYear() getter applies -1900
25657 * unconditionally.
25658 */
25659 duk_push_int(ctx, (flags_and_idx & DUK_DATE_FLAG_SUB1900) ? parts[idx_part] - 1900 : parts[idx_part]);
25660 return 1;
25661}
25662
25663/* Helper for component setter calls: check 'this' binding, get the
25664 * internal time value, split it into parts (either as UTC time or
25665 * local time), modify one or more components as specified, recompute
25666 * the time value, set it as the internal value. Finally, push the
25667 * new time value as a return value to the value stack and return 1
25668 * (caller can then tail call us).
25669 */
25670DUK_LOCAL duk_ret_t duk__set_part_helper(duk_context *ctx, duk_small_uint_t flags_and_maxnargs) {
25671 duk_double_t d;
25672 duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
25673 duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
25674 duk_idx_t nargs;
25675 duk_small_uint_t maxnargs = (duk_small_uint_t) (flags_and_maxnargs >> DUK_DATE_FLAG_VALUE_SHIFT); /* unpack args */
25676 duk_small_uint_t idx_first, idx;
25677 duk_small_uint_t i;
25678
25679 nargs = duk_get_top(ctx);
25680 d = duk__push_this_get_timeval(ctx, flags_and_maxnargs);
25681 DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
25682
25683 if (DUK_ISFINITE(d)) {
25684 duk_bi_date_timeval_to_parts(d, parts, dparts, flags_and_maxnargs);
25685 } else {
25686 /* NaN timevalue: we need to coerce the arguments, but
25687 * the resulting internal timestamp needs to remain NaN.
25688 * This works but is not pretty: parts and dparts will
25689 * be partially uninitialized, but we only write to them.
25690 */
25691 }
25692
25693 /*
25694 * Determining which datetime components to overwrite based on
25695 * stack arguments is a bit complicated, but important to factor
25696 * out from setters themselves for compactness.
25697 *
25698 * If DUK_DATE_FLAG_TIMESETTER, maxnargs indicates setter type:
25699 *
25700 * 1 -> millisecond
25701 * 2 -> second, [millisecond]
25702 * 3 -> minute, [second], [millisecond]
25703 * 4 -> hour, [minute], [second], [millisecond]
25704 *
25705 * Else:
25706 *
25707 * 1 -> date
25708 * 2 -> month, [date]
25709 * 3 -> year, [month], [date]
25710 *
25711 * By comparing nargs and maxnargs (and flags) we know which
25712 * components to override. We rely on part index ordering.
25713 */
25714
25715 if (flags_and_maxnargs & DUK_DATE_FLAG_TIMESETTER) {
25716 DUK_ASSERT(maxnargs >= 1 && maxnargs <= 4);
25717 idx_first = DUK_DATE_IDX_MILLISECOND - (maxnargs - 1);
25718 } else {
25719 DUK_ASSERT(maxnargs >= 1 && maxnargs <= 3);
25720 idx_first = DUK_DATE_IDX_DAY - (maxnargs - 1);
25721 }
25722 DUK_ASSERT_DISABLE(idx_first >= 0); /* unsigned */
25723 DUK_ASSERT(idx_first < DUK_DATE_IDX_NUM_PARTS);
25724
25725 for (i = 0; i < maxnargs; i++) {
25726 if ((duk_idx_t) i >= nargs) {
25727 /* no argument given -> leave components untouched */
25728 break;
25729 }
25730 idx = idx_first + i;
25731 DUK_ASSERT_DISABLE(idx >= 0); /* unsigned */
25732 DUK_ASSERT(idx < DUK_DATE_IDX_NUM_PARTS);
25733
25734 if (idx == DUK_DATE_IDX_YEAR && (flags_and_maxnargs & DUK_DATE_FLAG_YEAR_FIXUP)) {
25735 duk__twodigit_year_fixup(ctx, (duk_idx_t) i);
25736 }
25737
25738 dparts[idx] = duk_to_number(ctx, i);
25739
25740 if (idx == DUK_DATE_IDX_DAY) {
25741 /* Day-of-month is one-based in the API, but zero-based
25742 * internally, so fix here. Note that month is zero-based
25743 * both in the API and internally.
25744 */
25745 /* SCANBUILD: complains about use of uninitialized values.
25746 * The complaint is correct, but operating in undefined
25747 * values here is intentional in some cases and the caller
25748 * ignores the results.
25749 */
25750 dparts[idx] -= 1.0;
25751 }
25752 }
25753
25754 /* Leaves new timevalue on stack top and returns 1, which is correct
25755 * for part setters.
25756 */
25757 if (DUK_ISFINITE(d)) {
25758 return duk__set_this_timeval_from_dparts(ctx, dparts, flags_and_maxnargs);
25759 } else {
25760 /* Internal timevalue is already NaN, so don't touch it. */
25761 duk_push_nan(ctx);
25762 return 1;
25763 }
25764}
25765
25766/* Apply ToNumber() to specified index; if ToInteger(val) in [0,99], add
25767 * 1900 and replace value at idx_val.
25768 */
25769DUK_LOCAL void duk__twodigit_year_fixup(duk_context *ctx, duk_idx_t idx_val) {
25770 duk_double_t d;
25771
25772 /* XXX: idx_val would fit into 16 bits, but using duk_small_uint_t
25773 * might not generate better code due to casting.
25774 */
25775
25776 /* E5 Sections 15.9.3.1, B.2.4, B.2.5 */
25777 duk_to_number(ctx, idx_val);
25778 if (duk_is_nan(ctx, idx_val)) {
25779 return;
25780 }
25781 duk_dup(ctx, idx_val);
25782 duk_to_int(ctx, -1);
25783 d = duk_get_number(ctx, -1); /* get as double to handle huge numbers correctly */
25784 if (d >= 0.0 && d <= 99.0) {
25785 d += 1900.0;
25786 duk_push_number(ctx, d);
25787 duk_replace(ctx, idx_val);
25788 }
25789 duk_pop(ctx);
25790}
25791
25792/* Set datetime parts from stack arguments, defaulting any missing values.
25793 * Day-of-week is not set; it is not required when setting the time value.
25794 */
25795DUK_LOCAL void duk__set_parts_from_args(duk_context *ctx, duk_double_t *dparts, duk_idx_t nargs) {
25796 duk_double_t d;
25797 duk_small_uint_t i;
25798 duk_small_uint_t idx;
25799
25800 /* Causes a ToNumber() coercion, but doesn't break coercion order since
25801 * year is coerced first anyway.
25802 */
25803 duk__twodigit_year_fixup(ctx, 0);
25804
25805 /* There are at most 7 args, but we use 8 here so that also
25806 * DUK_DATE_IDX_WEEKDAY gets initialized (to zero) to avoid the potential
25807 * for any Valgrind gripes later.
25808 */
25809 for (i = 0; i < 8; i++) {
25810 /* Note: rely on index ordering */
25811 idx = DUK_DATE_IDX_YEAR + i;
25812 if ((duk_idx_t) i < nargs) {
25813 d = duk_to_number(ctx, (duk_idx_t) i);
25814 if (idx == DUK_DATE_IDX_DAY) {
25815 /* Convert day from one-based to zero-based (internal). This may
25816 * cause the day part to be negative, which is OK.
25817 */
25818 d -= 1.0;
25819 }
25820 } else {
25821 /* All components default to 0 except day-of-month which defaults
25822 * to 1. However, because our internal day-of-month is zero-based,
25823 * it also defaults to zero here.
25824 */
25825 d = 0.0;
25826 }
25827 dparts[idx] = d;
25828 }
25829
25830 DUK_DDD(DUK_DDDPRINT("parts from args -> %lf %lf %lf %lf %lf %lf %lf %lf",
25831 (double) dparts[0], (double) dparts[1],
25832 (double) dparts[2], (double) dparts[3],
25833 (double) dparts[4], (double) dparts[5],
25834 (double) dparts[6], (double) dparts[7]));
25835}
25836
25837/*
25838 * Helper to format a time value into caller buffer, used by logging.
25839 * 'out_buf' must be at least DUK_BI_DATE_ISO8601_BUFSIZE long.
25840 */
25841
25842DUK_INTERNAL void duk_bi_date_format_timeval(duk_double_t timeval, duk_uint8_t *out_buf) {
25843 duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
25844
25845 duk_bi_date_timeval_to_parts(timeval,
25846 parts,
25847 NULL,
25848 DUK_DATE_FLAG_ONEBASED);
25849
25850 duk__format_parts_iso8601(parts,
25851 0 /*tzoffset*/,
25852 DUK_DATE_FLAG_TOSTRING_DATE |
25853 DUK_DATE_FLAG_TOSTRING_TIME |
25854 DUK_DATE_FLAG_SEP_T /*flags*/,
25855 out_buf);
25856}
25857
25858/*
25859 * Indirect magic value lookup for Date methods.
25860 *
25861 * Date methods don't put their control flags into the function magic value
25862 * because they wouldn't fit into a LIGHTFUNC's magic field. Instead, the
25863 * magic value is set to an index pointing to the array of control flags
25864 * below.
25865 *
25866 * This must be kept in strict sync with genbuiltins.py!
25867 */
25868
25869static duk_uint16_t duk__date_magics[] = {
25870 /* 0: toString */
25871 DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_LOCALTIME,
25872
25873 /* 1: toDateString */
25874 DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_LOCALTIME,
25875
25876 /* 2: toTimeString */
25877 DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_LOCALTIME,
25878
25879 /* 3: toLocaleString */
25880 DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_TOSTRING_LOCALE + DUK_DATE_FLAG_LOCALTIME,
25881
25882 /* 4: toLocaleDateString */
25883 DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_LOCALE + DUK_DATE_FLAG_LOCALTIME,
25884
25885 /* 5: toLocaleTimeString */
25886 DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_TOSTRING_LOCALE + DUK_DATE_FLAG_LOCALTIME,
25887
25888 /* 6: toUTCString */
25889 DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME,
25890
25891 /* 7: toISOString */
25892 DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_NAN_TO_RANGE_ERROR + DUK_DATE_FLAG_SEP_T,
25893
25894 /* 8: getFullYear */
25895 DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_YEAR << DUK_DATE_FLAG_VALUE_SHIFT),
25896
25897 /* 9: getUTCFullYear */
25898 0 + (DUK_DATE_IDX_YEAR << DUK_DATE_FLAG_VALUE_SHIFT),
25899
25900 /* 10: getMonth */
25901 DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_MONTH << DUK_DATE_FLAG_VALUE_SHIFT),
25902
25903 /* 11: getUTCMonth */
25904 0 + (DUK_DATE_IDX_MONTH << DUK_DATE_FLAG_VALUE_SHIFT),
25905
25906 /* 12: getDate */
25907 DUK_DATE_FLAG_ONEBASED + DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_DAY << DUK_DATE_FLAG_VALUE_SHIFT),
25908
25909 /* 13: getUTCDate */
25910 DUK_DATE_FLAG_ONEBASED + (DUK_DATE_IDX_DAY << DUK_DATE_FLAG_VALUE_SHIFT),
25911
25912 /* 14: getDay */
25913 DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_WEEKDAY << DUK_DATE_FLAG_VALUE_SHIFT),
25914
25915 /* 15: getUTCDay */
25916 0 + (DUK_DATE_IDX_WEEKDAY << DUK_DATE_FLAG_VALUE_SHIFT),
25917
25918 /* 16: getHours */
25919 DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_HOUR << DUK_DATE_FLAG_VALUE_SHIFT),
25920
25921 /* 17: getUTCHours */
25922 0 + (DUK_DATE_IDX_HOUR << DUK_DATE_FLAG_VALUE_SHIFT),
25923
25924 /* 18: getMinutes */
25925 DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_MINUTE << DUK_DATE_FLAG_VALUE_SHIFT),
25926
25927 /* 19: getUTCMinutes */
25928 0 + (DUK_DATE_IDX_MINUTE << DUK_DATE_FLAG_VALUE_SHIFT),
25929
25930 /* 20: getSeconds */
25931 DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_SECOND << DUK_DATE_FLAG_VALUE_SHIFT),
25932
25933 /* 21: getUTCSeconds */
25934 0 + (DUK_DATE_IDX_SECOND << DUK_DATE_FLAG_VALUE_SHIFT),
25935
25936 /* 22: getMilliseconds */
25937 DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_MILLISECOND << DUK_DATE_FLAG_VALUE_SHIFT),
25938
25939 /* 23: getUTCMilliseconds */
25940 0 + (DUK_DATE_IDX_MILLISECOND << DUK_DATE_FLAG_VALUE_SHIFT),
25941
25942 /* 24: setMilliseconds */
25943 DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (1 << DUK_DATE_FLAG_VALUE_SHIFT),
25944
25945 /* 25: setUTCMilliseconds */
25946 DUK_DATE_FLAG_TIMESETTER + (1 << DUK_DATE_FLAG_VALUE_SHIFT),
25947
25948 /* 26: setSeconds */
25949 DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (2 << DUK_DATE_FLAG_VALUE_SHIFT),
25950
25951 /* 27: setUTCSeconds */
25952 DUK_DATE_FLAG_TIMESETTER + (2 << DUK_DATE_FLAG_VALUE_SHIFT),
25953
25954 /* 28: setMinutes */
25955 DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
25956
25957 /* 29: setUTCMinutes */
25958 DUK_DATE_FLAG_TIMESETTER + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
25959
25960 /* 30: setHours */
25961 DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (4 << DUK_DATE_FLAG_VALUE_SHIFT),
25962
25963 /* 31: setUTCHours */
25964 DUK_DATE_FLAG_TIMESETTER + (4 << DUK_DATE_FLAG_VALUE_SHIFT),
25965
25966 /* 32: setDate */
25967 DUK_DATE_FLAG_LOCALTIME + (1 << DUK_DATE_FLAG_VALUE_SHIFT),
25968
25969 /* 33: setUTCDate */
25970 0 + (1 << DUK_DATE_FLAG_VALUE_SHIFT),
25971
25972 /* 34: setMonth */
25973 DUK_DATE_FLAG_LOCALTIME + (2 << DUK_DATE_FLAG_VALUE_SHIFT),
25974
25975 /* 35: setUTCMonth */
25976 0 + (2 << DUK_DATE_FLAG_VALUE_SHIFT),
25977
25978 /* 36: setFullYear */
25979 DUK_DATE_FLAG_NAN_TO_ZERO + DUK_DATE_FLAG_LOCALTIME + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
25980
25981 /* 37: setUTCFullYear */
25982 DUK_DATE_FLAG_NAN_TO_ZERO + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
25983
25984 /* 38: getYear */
25985 DUK_DATE_FLAG_LOCALTIME + DUK_DATE_FLAG_SUB1900 + (DUK_DATE_IDX_YEAR << DUK_DATE_FLAG_VALUE_SHIFT),
25986
25987 /* 39: setYear */
25988 DUK_DATE_FLAG_NAN_TO_ZERO + DUK_DATE_FLAG_YEAR_FIXUP + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
25989};
25990
25991DUK_LOCAL duk_small_uint_t duk__date_get_indirect_magic(duk_context *ctx) {
25992 duk_small_int_t magicidx = (duk_small_uint_t) duk_get_current_magic(ctx);
25993 DUK_ASSERT(magicidx >= 0 && magicidx < (duk_small_int_t) (sizeof(duk__date_magics) / sizeof(duk_uint16_t)));
25994 return (duk_small_uint_t) duk__date_magics[magicidx];
25995}
25996
25997/*
25998 * Constructor calls
25999 */
26000
26001DUK_INTERNAL duk_ret_t duk_bi_date_constructor(duk_context *ctx) {
26002 duk_idx_t nargs = duk_get_top(ctx);
26003 duk_bool_t is_cons = duk_is_constructor_call(ctx);
26004 duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
26005 duk_double_t d;
26006
26007 DUK_DDD(DUK_DDDPRINT("Date constructor, nargs=%ld, is_cons=%ld", (long) nargs, (long) is_cons));
26008
26009 duk_push_object_helper(ctx,
26010 DUK_HOBJECT_FLAG_EXTENSIBLE |
26011 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATE),
26012 DUK_BIDX_DATE_PROTOTYPE);
26013
26014 /* Unlike most built-ins, the internal [[PrimitiveValue]] of a Date
26015 * is mutable.
26016 */
26017
26018 if (nargs == 0 || !is_cons) {
26019 d = duk__timeclip(DUK_USE_DATE_GET_NOW(ctx));
26020 duk_push_number(ctx, d);
26021 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W);
26022 if (!is_cons) {
26023 /* called as a normal function: return new Date().toString() */
26024 duk_to_string(ctx, -1);
26025 }
26026 return 1;
26027 } else if (nargs == 1) {
26028 duk_to_primitive(ctx, 0, DUK_HINT_NONE);
26029 if (duk_is_string(ctx, 0)) {
26030 duk__parse_string(ctx, duk_to_string(ctx, 0));
26031 duk_replace(ctx, 0); /* may be NaN */
26032 }
26033 d = duk__timeclip(duk_to_number(ctx, 0));
26034 duk_push_number(ctx, d);
26035 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W);
26036 return 1;
26037 }
26038
26039 duk__set_parts_from_args(ctx, dparts, nargs);
26040
26041 /* Parts are in local time, convert when setting. */
26042
26043 (void) duk__set_this_timeval_from_dparts(ctx, dparts, DUK_DATE_FLAG_LOCALTIME /*flags*/); /* -> [ ... this timeval ] */
26044 duk_pop(ctx); /* -> [ ... this ] */
26045 return 1;
26046}
26047
26048DUK_INTERNAL duk_ret_t duk_bi_date_constructor_parse(duk_context *ctx) {
26049 return duk__parse_string(ctx, duk_to_string(ctx, 0));
26050}
26051
26052DUK_INTERNAL duk_ret_t duk_bi_date_constructor_utc(duk_context *ctx) {
26053 duk_idx_t nargs = duk_get_top(ctx);
26054 duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
26055 duk_double_t d;
26056
26057 /* Behavior for nargs < 2 is implementation dependent: currently we'll
26058 * set a NaN time value (matching V8 behavior) in this case.
26059 */
26060
26061 if (nargs < 2) {
26062 duk_push_nan(ctx);
26063 } else {
26064 duk__set_parts_from_args(ctx, dparts, nargs);
26065 d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/);
26066 duk_push_number(ctx, d);
26067 }
26068 return 1;
26069}
26070
26071DUK_INTERNAL duk_ret_t duk_bi_date_constructor_now(duk_context *ctx) {
26072 duk_double_t d;
26073
26074 d = DUK_USE_DATE_GET_NOW(ctx);
26075 DUK_ASSERT(duk__timeclip(d) == d); /* TimeClip() should never be necessary */
26076 duk_push_number(ctx, d);
26077 return 1;
26078}
26079
26080/*
26081 * String/JSON conversions
26082 *
26083 * Human readable conversions are now basically ISO 8601 with a space
26084 * (instead of 'T') as the date/time separator. This is a good baseline
26085 * and is platform independent.
26086 *
26087 * A shared native helper to provide many conversions. Magic value contains
26088 * a set of flags. The helper provides:
26089 *
26090 * toString()
26091 * toDateString()
26092 * toTimeString()
26093 * toLocaleString()
26094 * toLocaleDateString()
26095 * toLocaleTimeString()
26096 * toUTCString()
26097 * toISOString()
26098 *
26099 * Notes:
26100 *
26101 * - Date.prototype.toGMTString() and Date.prototype.toUTCString() are
26102 * required to be the same Ecmascript function object (!), so it is
26103 * omitted from here.
26104 *
26105 * - Date.prototype.toUTCString(): E5.1 specification does not require a
26106 * specific format, but result should be human readable. The
26107 * specification suggests using ISO 8601 format with a space (instead
26108 * of 'T') separator if a more human readable format is not available.
26109 *
26110 * - Date.prototype.toISOString(): unlike other conversion functions,
26111 * toISOString() requires a RangeError for invalid date values.
26112 */
26113
26114DUK_INTERNAL duk_ret_t duk_bi_date_prototype_tostring_shared(duk_context *ctx) {
26115 duk_small_uint_t flags = duk__date_get_indirect_magic(ctx);
26116 return duk__to_string_helper(ctx, flags);
26117}
26118
26119DUK_INTERNAL duk_ret_t duk_bi_date_prototype_value_of(duk_context *ctx) {
26120 /* This native function is also used for Date.prototype.getTime()
26121 * as their behavior is identical.
26122 */
26123
26124 duk_double_t d = duk__push_this_get_timeval(ctx, 0 /*flags*/); /* -> [ this ] */
26125 DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
26126 duk_push_number(ctx, d);
26127 return 1;
26128}
26129
26130DUK_INTERNAL duk_ret_t duk_bi_date_prototype_to_json(duk_context *ctx) {
26131 /* Note: toJSON() is a generic function which works even if 'this'
26132 * is not a Date. The sole argument is ignored.
26133 */
26134
26135 duk_push_this(ctx);
26136 duk_to_object(ctx, -1);
26137
26138 duk_dup_top(ctx);
26139 duk_to_primitive(ctx, -1, DUK_HINT_NUMBER);
26140 if (duk_is_number(ctx, -1)) {
26141 duk_double_t d = duk_get_number(ctx, -1);
26142 if (!DUK_ISFINITE(d)) {
26143 duk_push_null(ctx);
26144 return 1;
26145 }
26146 }
26147 duk_pop(ctx);
26148
26149 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_TO_ISO_STRING);
26150 duk_dup(ctx, -2); /* -> [ O toIsoString O ] */
26151 duk_call_method(ctx, 0);
26152 return 1;
26153}
26154
26155/*
26156 * Getters.
26157 *
26158 * Implementing getters is quite easy. The internal time value is either
26159 * NaN, or represents milliseconds (without fractions) from Jan 1, 1970.
26160 * The internal time value can be converted to integer parts, and each
26161 * part will be normalized and will fit into a 32-bit signed integer.
26162 *
26163 * A shared native helper to provide all getters. Magic value contains
26164 * a set of flags and also packs the date component index argument. The
26165 * helper provides:
26166 *
26167 * getFullYear()
26168 * getUTCFullYear()
26169 * getMonth()
26170 * getUTCMonth()
26171 * getDate()
26172 * getUTCDate()
26173 * getDay()
26174 * getUTCDay()
26175 * getHours()
26176 * getUTCHours()
26177 * getMinutes()
26178 * getUTCMinutes()
26179 * getSeconds()
26180 * getUTCSeconds()
26181 * getMilliseconds()
26182 * getUTCMilliseconds()
26183 * getYear()
26184 *
26185 * Notes:
26186 *
26187 * - Date.prototype.getDate(): 'date' means day-of-month, and is
26188 * zero-based in internal calculations but public API expects it to
26189 * be one-based.
26190 *
26191 * - Date.prototype.getTime() and Date.prototype.valueOf() have identical
26192 * behavior. They have separate function objects, but share the same C
26193 * function (duk_bi_date_prototype_value_of).
26194 */
26195
26196DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_shared(duk_context *ctx) {
26197 duk_small_uint_t flags_and_idx = duk__date_get_indirect_magic(ctx);
26198 return duk__get_part_helper(ctx, flags_and_idx);
26199}
26200
26201DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_context *ctx) {
26202 /*
26203 * Return (t - LocalTime(t)) in minutes:
26204 *
26205 * t - LocalTime(t) = t - (t + LocalTZA + DaylightSavingTA(t))
26206 * = -(LocalTZA + DaylightSavingTA(t))
26207 *
26208 * where DaylightSavingTA() is checked for time 't'.
26209 *
26210 * Note that the sign of the result is opposite to common usage,
26211 * e.g. for EE(S)T which normally is +2h or +3h from UTC, this
26212 * function returns -120 or -180.
26213 *
26214 */
26215
26216 duk_double_t d;
26217 duk_int_t tzoffset;
26218
26219 /* Note: DST adjustment is determined using UTC time. */
26220 d = duk__push_this_get_timeval(ctx, 0 /*flags*/);
26221 DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
26222 if (DUK_ISNAN(d)) {
26223 duk_push_nan(ctx);
26224 } else {
26225 DUK_ASSERT(DUK_ISFINITE(d));
26226 tzoffset = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d);
26227 duk_push_int(ctx, -tzoffset / 60);
26228 }
26229 return 1;
26230}
26231
26232/*
26233 * Setters.
26234 *
26235 * Setters are a bit more complicated than getters. Component setters
26236 * break down the current time value into its (normalized) component
26237 * parts, replace one or more components with -unnormalized- new values,
26238 * and the components are then converted back into a time value. As an
26239 * example of using unnormalized values:
26240 *
26241 * var d = new Date(1234567890);
26242 *
26243 * is equivalent to:
26244 *
26245 * var d = new Date(0);
26246 * d.setUTCMilliseconds(1234567890);
26247 *
26248 * A shared native helper to provide almost all setters. Magic value
26249 * contains a set of flags and also packs the "maxnargs" argument. The
26250 * helper provides:
26251 *
26252 * setMilliseconds()
26253 * setUTCMilliseconds()
26254 * setSeconds()
26255 * setUTCSeconds()
26256 * setMinutes()
26257 * setUTCMinutes()
26258 * setHours()
26259 * setUTCHours()
26260 * setDate()
26261 * setUTCDate()
26262 * setMonth()
26263 * setUTCMonth()
26264 * setFullYear()
26265 * setUTCFullYear()
26266 * setYear()
26267 *
26268 * Notes:
26269 *
26270 * - Date.prototype.setYear() (Section B addition): special year check
26271 * is omitted. NaN / Infinity will just flow through and ultimately
26272 * result in a NaN internal time value.
26273 *
26274 * - Date.prototype.setYear() does not have optional arguments for
26275 * setting month and day-in-month (like setFullYear()), but we indicate
26276 * 'maxnargs' to be 3 to get the year written to the correct component
26277 * index in duk__set_part_helper(). The function has nargs == 1, so only
26278 * the year will be set regardless of actual argument count.
26279 */
26280
26281DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_shared(duk_context *ctx) {
26282 duk_small_uint_t flags_and_maxnargs = duk__date_get_indirect_magic(ctx);
26283 return duk__set_part_helper(ctx, flags_and_maxnargs);
26284}
26285
26286DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_time(duk_context *ctx) {
26287 duk_double_t d;
26288
26289 (void) duk__push_this_get_timeval(ctx, 0 /*flags*/); /* -> [ timeval this ] */
26290 d = duk__timeclip(duk_to_number(ctx, 0));
26291 duk_push_number(ctx, d);
26292 duk_dup_top(ctx);
26293 duk_put_prop_stridx(ctx, -3, DUK_STRIDX_INT_VALUE); /* -> [ timeval this timeval ] */
26294
26295 return 1;
26296}
7c673cae
FG
26297/*
26298 * Unix-like Date providers
26299 *
26300 * Generally useful Unix / POSIX / ANSI Date providers.
26301 */
26302
26303/* include removed: duk_internal.h */
26304
26305/* The necessary #includes are in place in duk_config.h. */
26306
26307/* Buffer sizes for some UNIX calls. Larger than strictly necessary
26308 * to avoid Valgrind errors.
26309 */
26310#define DUK__STRPTIME_BUF_SIZE 64
26311#define DUK__STRFTIME_BUF_SIZE 64
26312
26313#if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY)
26314/* Get current Ecmascript time (= UNIX/Posix time, but in milliseconds). */
26315DUK_INTERNAL duk_double_t duk_bi_date_get_now_gettimeofday(duk_context *ctx) {
26316 duk_hthread *thr = (duk_hthread *) ctx;
26317 struct timeval tv;
26318 duk_double_t d;
26319
26320 if (gettimeofday(&tv, NULL) != 0) {
11fdf7f2 26321 DUK_ERROR_INTERNAL_DEFMSG(thr);
7c673cae
FG
26322 }
26323
26324 d = ((duk_double_t) tv.tv_sec) * 1000.0 +
26325 ((duk_double_t) (tv.tv_usec / 1000));
26326 DUK_ASSERT(DUK_FLOOR(d) == d); /* no fractions */
26327
26328 return d;
26329}
26330#endif /* DUK_USE_DATE_NOW_GETTIMEOFDAY */
26331
26332#if defined(DUK_USE_DATE_NOW_TIME)
26333/* Not a very good provider: only full seconds are available. */
26334DUK_INTERNAL duk_double_t duk_bi_date_get_now_time(duk_context *ctx) {
11fdf7f2
TL
26335 time_t t;
26336
26337 DUK_UNREF(ctx);
26338 t = time(NULL);
7c673cae
FG
26339 return ((duk_double_t) t) * 1000.0;
26340}
26341#endif /* DUK_USE_DATE_NOW_TIME */
26342
26343#if defined(DUK_USE_DATE_TZO_GMTIME) || defined(DUK_USE_DATE_TZO_GMTIME_R)
26344/* Get local time offset (in seconds) for a certain (UTC) instant 'd'. */
26345DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) {
26346 time_t t, t1, t2;
26347 duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
26348 duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
26349 struct tm tms[2];
26350#ifdef DUK_USE_DATE_TZO_GMTIME
26351 struct tm *tm_ptr;
26352#endif
26353
26354 /* For NaN/inf, the return value doesn't matter. */
26355 if (!DUK_ISFINITE(d)) {
26356 return 0;
26357 }
26358
26359 /* If not within Ecmascript range, some integer time calculations
26360 * won't work correctly (and some asserts will fail), so bail out
26361 * if so. This fixes test-bug-date-insane-setyear.js. There is
26362 * a +/- 24h leeway in this range check to avoid a test262 corner
26363 * case documented in test-bug-date-timeval-edges.js.
26364 */
26365 if (!duk_bi_date_timeval_in_leeway_range(d)) {
26366 DUK_DD(DUK_DDPRINT("timeval not within valid range, skip tzoffset computation to avoid integer overflows"));
26367 return 0;
26368 }
26369
26370 /*
26371 * This is a bit tricky to implement portably. The result depends
26372 * on the timestamp (specifically, DST depends on the timestamp).
26373 * If e.g. UNIX APIs are used, they'll have portability issues with
26374 * very small and very large years.
26375 *
26376 * Current approach:
26377 *
26378 * - Stay within portable UNIX limits by using equivalent year mapping.
26379 * Avoid year 1970 and 2038 as some conversions start to fail, at
26380 * least on some platforms. Avoiding 1970 means that there are
26381 * currently DST discrepancies for 1970.
26382 *
26383 * - Create a UTC and local time breakdowns from 't'. Then create
26384 * a time_t using gmtime() and localtime() and compute the time
26385 * difference between the two.
26386 *
26387 * Equivalent year mapping (E5 Section 15.9.1.8):
26388 *
26389 * If the host environment provides functionality for determining
26390 * daylight saving time, the implementation of ECMAScript is free
26391 * to map the year in question to an equivalent year (same
26392 * leap-year-ness and same starting week day for the year) for which
26393 * the host environment provides daylight saving time information.
26394 * The only restriction is that all equivalent years should produce
26395 * the same result.
26396 *
26397 * This approach is quite reasonable but not entirely correct, e.g.
26398 * the specification also states (E5 Section 15.9.1.8):
26399 *
26400 * The implementation of ECMAScript should not try to determine
26401 * whether the exact time was subject to daylight saving time, but
26402 * just whether daylight saving time would have been in effect if
26403 * the _current daylight saving time algorithm_ had been used at the
26404 * time. This avoids complications such as taking into account the
26405 * years that the locale observed daylight saving time year round.
26406 *
26407 * Since we rely on the platform APIs for conversions between local
26408 * time and UTC, we can't guarantee the above. Rather, if the platform
26409 * has historical DST rules they will be applied. This seems to be the
26410 * general preferred direction in Ecmascript standardization (or at least
26411 * implementations) anyway, and even the equivalent year mapping should
26412 * be disabled if the platform is known to handle DST properly for the
26413 * full Ecmascript range.
26414 *
26415 * The following has useful discussion and links:
26416 *
26417 * https://bugzilla.mozilla.org/show_bug.cgi?id=351066
26418 */
26419
26420 duk_bi_date_timeval_to_parts(d, parts, dparts, DUK_DATE_FLAG_EQUIVYEAR /*flags*/);
26421 DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] >= 1970 && parts[DUK_DATE_IDX_YEAR] <= 2038);
26422
26423 d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/);
26424 DUK_ASSERT(d >= 0 && d < 2147483648.0 * 1000.0); /* unsigned 31-bit range */
26425 t = (time_t) (d / 1000.0);
26426 DUK_DDD(DUK_DDDPRINT("timeval: %lf -> time_t %ld", (double) d, (long) t));
26427
7c673cae
FG
26428 DUK_MEMZERO((void *) tms, sizeof(struct tm) * 2);
26429
26430#if defined(DUK_USE_DATE_TZO_GMTIME_R)
26431 (void) gmtime_r(&t, &tms[0]);
26432 (void) localtime_r(&t, &tms[1]);
26433#elif defined(DUK_USE_DATE_TZO_GMTIME)
26434 tm_ptr = gmtime(&t);
26435 DUK_MEMCPY((void *) &tms[0], tm_ptr, sizeof(struct tm));
26436 tm_ptr = localtime(&t);
26437 DUK_MEMCPY((void *) &tms[1], tm_ptr, sizeof(struct tm));
26438#else
26439#error internal error
26440#endif
26441 DUK_DDD(DUK_DDDPRINT("gmtime result: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld,"
26442 "wday:%ld,yday:%ld,isdst:%ld}",
26443 (long) tms[0].tm_sec, (long) tms[0].tm_min, (long) tms[0].tm_hour,
26444 (long) tms[0].tm_mday, (long) tms[0].tm_mon, (long) tms[0].tm_year,
26445 (long) tms[0].tm_wday, (long) tms[0].tm_yday, (long) tms[0].tm_isdst));
26446 DUK_DDD(DUK_DDDPRINT("localtime result: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld,"
26447 "wday:%ld,yday:%ld,isdst:%ld}",
26448 (long) tms[1].tm_sec, (long) tms[1].tm_min, (long) tms[1].tm_hour,
26449 (long) tms[1].tm_mday, (long) tms[1].tm_mon, (long) tms[1].tm_year,
26450 (long) tms[1].tm_wday, (long) tms[1].tm_yday, (long) tms[1].tm_isdst));
26451
11fdf7f2
TL
26452 /* tm_isdst is both an input and an output to mktime(), use 0 to
26453 * avoid DST handling in mktime():
26454 * - https://github.com/svaarala/duktape/issues/406
26455 * - http://stackoverflow.com/questions/8558919/mktime-and-tm-isdst
26456 */
26457 tms[0].tm_isdst = 0;
26458 tms[1].tm_isdst = 0;
7c673cae
FG
26459 t1 = mktime(&tms[0]); /* UTC */
26460 t2 = mktime(&tms[1]); /* local */
26461 if (t1 == (time_t) -1 || t2 == (time_t) -1) {
26462 /* This check used to be for (t < 0) but on some platforms
26463 * time_t is unsigned and apparently the proper way to detect
26464 * an mktime() error return is the cast above. See e.g.:
26465 * http://pubs.opengroup.org/onlinepubs/009695299/functions/mktime.html
26466 */
26467 goto error;
26468 }
7c673cae
FG
26469 DUK_DDD(DUK_DDDPRINT("t1=%ld (utc), t2=%ld (local)", (long) t1, (long) t2));
26470
26471 /* Compute final offset in seconds, positive if local time ahead of
26472 * UTC (returned value is UTC-to-local offset).
26473 *
26474 * difftime() returns a double, so coercion to int generates quite
26475 * a lot of code. Direct subtraction is not portable, however.
26476 * XXX: allow direct subtraction on known platforms.
26477 */
26478#if 0
26479 return (duk_int_t) (t2 - t1);
26480#endif
26481 return (duk_int_t) difftime(t2, t1);
26482
26483 error:
26484 /* XXX: return something more useful, so that caller can throw? */
26485 DUK_D(DUK_DPRINT("mktime() failed, d=%lf", (double) d));
26486 return 0;
26487}
26488#endif /* DUK_USE_DATE_TZO_GMTIME */
26489
26490#if defined(DUK_USE_DATE_PRS_STRPTIME)
26491DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_strptime(duk_context *ctx, const char *str) {
26492 struct tm tm;
26493 time_t t;
26494 char buf[DUK__STRPTIME_BUF_SIZE];
26495
26496 /* copy to buffer with spare to avoid Valgrind gripes from strptime */
26497 DUK_ASSERT(str != NULL);
26498 DUK_MEMZERO(buf, sizeof(buf)); /* valgrind whine without this */
26499 DUK_SNPRINTF(buf, sizeof(buf), "%s", (const char *) str);
26500 buf[sizeof(buf) - 1] = (char) 0;
26501
26502 DUK_DDD(DUK_DDDPRINT("parsing: '%s'", (const char *) buf));
26503
26504 DUK_MEMZERO(&tm, sizeof(tm));
26505 if (strptime((const char *) buf, "%c", &tm) != NULL) {
26506 DUK_DDD(DUK_DDDPRINT("before mktime: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld,"
26507 "wday:%ld,yday:%ld,isdst:%ld}",
26508 (long) tm.tm_sec, (long) tm.tm_min, (long) tm.tm_hour,
26509 (long) tm.tm_mday, (long) tm.tm_mon, (long) tm.tm_year,
26510 (long) tm.tm_wday, (long) tm.tm_yday, (long) tm.tm_isdst));
26511 tm.tm_isdst = -1; /* negative: dst info not available */
26512
26513 t = mktime(&tm);
26514 DUK_DDD(DUK_DDDPRINT("mktime() -> %ld", (long) t));
26515 if (t >= 0) {
26516 duk_push_number(ctx, ((duk_double_t) t) * 1000.0);
26517 return 1;
26518 }
26519 }
26520
26521 return 0;
26522}
26523#endif /* DUK_USE_DATE_PRS_STRPTIME */
26524
26525#if defined(DUK_USE_DATE_PRS_GETDATE)
26526DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_getdate(duk_context *ctx, const char *str) {
26527 struct tm tm;
26528 duk_small_int_t rc;
26529 time_t t;
26530
26531 /* For this to work, DATEMSK must be set, so this is not very
26532 * convenient for an embeddable interpreter.
26533 */
26534
26535 DUK_MEMZERO(&tm, sizeof(struct tm));
26536 rc = (duk_small_int_t) getdate_r(str, &tm);
26537 DUK_DDD(DUK_DDDPRINT("getdate_r() -> %ld", (long) rc));
26538
26539 if (rc == 0) {
26540 t = mktime(&tm);
26541 DUK_DDD(DUK_DDDPRINT("mktime() -> %ld", (long) t));
26542 if (t >= 0) {
26543 duk_push_number(ctx, (duk_double_t) t);
26544 return 1;
26545 }
26546 }
26547
26548 return 0;
26549}
26550#endif /* DUK_USE_DATE_PRS_GETDATE */
26551
26552#if defined(DUK_USE_DATE_FMT_STRFTIME)
26553DUK_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) {
26554 char buf[DUK__STRFTIME_BUF_SIZE];
26555 struct tm tm;
26556 const char *fmt;
26557
26558 DUK_UNREF(tzoffset);
26559
26560 /* If the platform doesn't support the entire Ecmascript range, we need
26561 * to return 0 so that the caller can fall back to the default formatter.
26562 *
26563 * For now, assume that if time_t is 8 bytes or more, the whole Ecmascript
26564 * range is supported. For smaller time_t values (4 bytes in practice),
26565 * assumes that the signed 32-bit range is supported.
26566 *
26567 * XXX: detect this more correctly per platform. The size of time_t is
26568 * probably not an accurate guarantee of strftime() supporting or not
26569 * supporting a large time range (the full Ecmascript range).
26570 */
26571 if (sizeof(time_t) < 8 &&
26572 (parts[DUK_DATE_IDX_YEAR] < 1970 || parts[DUK_DATE_IDX_YEAR] > 2037)) {
26573 /* be paranoid for 32-bit time values (even avoiding negative ones) */
26574 return 0;
26575 }
26576
26577 DUK_MEMZERO(&tm, sizeof(tm));
26578 tm.tm_sec = parts[DUK_DATE_IDX_SECOND];
26579 tm.tm_min = parts[DUK_DATE_IDX_MINUTE];
26580 tm.tm_hour = parts[DUK_DATE_IDX_HOUR];
26581 tm.tm_mday = parts[DUK_DATE_IDX_DAY]; /* already one-based */
26582 tm.tm_mon = parts[DUK_DATE_IDX_MONTH] - 1; /* one-based -> zero-based */
26583 tm.tm_year = parts[DUK_DATE_IDX_YEAR] - 1900;
26584 tm.tm_wday = parts[DUK_DATE_IDX_WEEKDAY];
26585 tm.tm_isdst = 0;
26586
26587 DUK_MEMZERO(buf, sizeof(buf));
26588 if ((flags & DUK_DATE_FLAG_TOSTRING_DATE) && (flags & DUK_DATE_FLAG_TOSTRING_TIME)) {
26589 fmt = "%c";
26590 } else if (flags & DUK_DATE_FLAG_TOSTRING_DATE) {
26591 fmt = "%x";
26592 } else {
26593 DUK_ASSERT(flags & DUK_DATE_FLAG_TOSTRING_TIME);
26594 fmt = "%X";
26595 }
26596 (void) strftime(buf, sizeof(buf) - 1, fmt, &tm);
26597 DUK_ASSERT(buf[sizeof(buf) - 1] == 0);
26598
26599 duk_push_string(ctx, buf);
26600 return 1;
26601}
26602#endif /* DUK_USE_DATE_FMT_STRFTIME */
26603
26604#undef DUK__STRPTIME_BUF_SIZE
26605#undef DUK__STRFTIME_BUF_SIZE
7c673cae
FG
26606/*
26607 * Windows Date providers
26608 *
26609 * Platform specific links:
26610 *
26611 * - http://msdn.microsoft.com/en-us/library/windows/desktop/ms725473(v=vs.85).aspx
26612 */
26613
26614/* include removed: duk_internal.h */
26615
26616/* The necessary #includes are in place in duk_config.h. */
26617
26618#if defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS)
26619/* Shared Windows helpers. */
26620DUK_LOCAL void duk__convert_systime_to_ularge(const SYSTEMTIME *st, ULARGE_INTEGER *res) {
26621 FILETIME ft;
26622 if (SystemTimeToFileTime(st, &ft) == 0) {
26623 DUK_D(DUK_DPRINT("SystemTimeToFileTime() failed, returning 0"));
26624 res->QuadPart = 0;
26625 } else {
26626 res->LowPart = ft.dwLowDateTime;
26627 res->HighPart = ft.dwHighDateTime;
26628 }
26629}
26630DUK_LOCAL void duk__set_systime_jan1970(SYSTEMTIME *st) {
26631 DUK_MEMZERO((void *) st, sizeof(*st));
26632 st->wYear = 1970;
26633 st->wMonth = 1;
26634 st->wDayOfWeek = 4; /* not sure whether or not needed; Thursday */
26635 st->wDay = 1;
26636 DUK_ASSERT(st->wHour == 0);
26637 DUK_ASSERT(st->wMinute == 0);
26638 DUK_ASSERT(st->wSecond == 0);
26639 DUK_ASSERT(st->wMilliseconds == 0);
26640}
26641#endif /* defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS) */
26642
26643#ifdef DUK_USE_DATE_NOW_WINDOWS
26644DUK_INTERNAL duk_double_t duk_bi_date_get_now_windows(duk_context *ctx) {
26645 /* Suggested step-by-step method from documentation of RtlTimeToSecondsSince1970:
26646 * http://msdn.microsoft.com/en-us/library/windows/desktop/ms724928(v=vs.85).aspx
26647 */
26648 SYSTEMTIME st1, st2;
26649 ULARGE_INTEGER tmp1, tmp2;
26650
26651 DUK_UNREF(ctx);
26652
26653 GetSystemTime(&st1);
26654 duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
26655
26656 duk__set_systime_jan1970(&st2);
26657 duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);
26658
26659 /* Difference is in 100ns units, convert to milliseconds w/o fractions */
26660 return (duk_double_t) ((tmp1.QuadPart - tmp2.QuadPart) / 10000LL);
26661}
26662#endif /* DUK_USE_DATE_NOW_WINDOWS */
26663
26664
26665#if defined(DUK_USE_DATE_TZO_WINDOWS)
26666DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d) {
26667 SYSTEMTIME st1;
26668 SYSTEMTIME st2;
26669 SYSTEMTIME st3;
26670 ULARGE_INTEGER tmp1;
26671 ULARGE_INTEGER tmp2;
26672 ULARGE_INTEGER tmp3;
26673 FILETIME ft1;
26674
26675 /* XXX: handling of timestamps outside Windows supported range.
26676 * How does Windows deal with dates before 1600? Does windows
26677 * support all Ecmascript years (like -200000 and +200000)?
26678 * Should equivalent year mapping be used here too? If so, use
26679 * a shared helper (currently integrated into timeval-to-parts).
26680 */
26681
26682 /* Use the approach described in "Remarks" of FileTimeToLocalFileTime:
26683 * http://msdn.microsoft.com/en-us/library/windows/desktop/ms724277(v=vs.85).aspx
26684 */
26685
26686 duk__set_systime_jan1970(&st1);
26687 duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
26688 tmp2.QuadPart = (ULONGLONG) (d * 10000.0); /* millisec -> 100ns units since jan 1, 1970 */
26689 tmp2.QuadPart += tmp1.QuadPart; /* input 'd' in Windows UTC, 100ns units */
26690
26691 ft1.dwLowDateTime = tmp2.LowPart;
26692 ft1.dwHighDateTime = tmp2.HighPart;
26693 FileTimeToSystemTime((const FILETIME *) &ft1, &st2);
26694 if (SystemTimeToTzSpecificLocalTime((LPTIME_ZONE_INFORMATION) NULL, &st2, &st3) == 0) {
26695 DUK_D(DUK_DPRINT("SystemTimeToTzSpecificLocalTime() failed, return tzoffset 0"));
26696 return 0;
26697 }
26698 duk__convert_systime_to_ularge((const SYSTEMTIME *) &st3, &tmp3);
26699
26700 /* Positive if local time ahead of UTC. */
26701 return (duk_int_t) (((LONGLONG) tmp3.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000000LL); /* seconds */
26702}
26703#endif /* DUK_USE_DATE_TZO_WINDOWS */
7c673cae
FG
26704/*
26705 * Duktape built-ins
26706 *
26707 * Size optimization note: it might seem that vararg multipurpose functions
26708 * like fin(), enc(), and dec() are not very size optimal, but using a single
26709 * user-visible Ecmascript function saves a lot of run-time footprint; each
26710 * Function instance takes >100 bytes. Using a shared native helper and a
26711 * 'magic' value won't save much if there are multiple Function instances
26712 * anyway.
26713 */
26714
26715/* include removed: duk_internal.h */
26716
26717/* Raw helper to extract internal information / statistics about a value.
26718 * The return values are version specific and must not expose anything
26719 * that would lead to security issues (e.g. exposing compiled function
26720 * 'data' buffer might be an issue). Currently only counts and sizes and
26721 * such are given so there should not be a security impact.
26722 */
26723DUK_INTERNAL duk_ret_t duk_bi_duktape_object_info(duk_context *ctx) {
26724 duk_hthread *thr = (duk_hthread *) ctx;
26725 duk_tval *tv;
26726 duk_heaphdr *h;
26727 duk_int_t i, n;
26728
26729 DUK_UNREF(thr);
26730
26731 /* result array */
26732 duk_push_array(ctx); /* -> [ val arr ] */
26733
26734 /* type tag (public) */
26735 duk_push_int(ctx, duk_get_type(ctx, 0));
26736
26737 /* address */
26738 tv = duk_get_tval(ctx, 0);
26739 DUK_ASSERT(tv != NULL); /* because arg count is 1 */
26740 if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
26741 h = DUK_TVAL_GET_HEAPHDR(tv);
26742 duk_push_pointer(ctx, (void *) h);
26743 } else {
26744 /* internal type tag */
26745 duk_push_int(ctx, (duk_int_t) DUK_TVAL_GET_TAG(tv));
26746 goto done;
26747 }
26748 DUK_ASSERT(h != NULL);
26749
26750 /* refcount */
26751#ifdef DUK_USE_REFERENCE_COUNTING
26752 duk_push_size_t(ctx, DUK_HEAPHDR_GET_REFCOUNT(h));
26753#else
26754 duk_push_undefined(ctx);
26755#endif
26756
26757 /* heaphdr size and additional allocation size, followed by
26758 * type specific stuff (with varying value count)
26759 */
26760 switch ((duk_small_int_t) DUK_HEAPHDR_GET_TYPE(h)) {
26761 case DUK_HTYPE_STRING: {
26762 duk_hstring *h_str = (duk_hstring *) h;
26763 duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hstring) + DUK_HSTRING_GET_BYTELEN(h_str) + 1));
26764 break;
26765 }
26766 case DUK_HTYPE_OBJECT: {
26767 duk_hobject *h_obj = (duk_hobject *) h;
26768 duk_small_uint_t hdr_size;
26769 if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h_obj)) {
26770 hdr_size = (duk_small_uint_t) sizeof(duk_hcompiledfunction);
26771 } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h_obj)) {
26772 hdr_size = (duk_small_uint_t) sizeof(duk_hnativefunction);
26773 } else if (DUK_HOBJECT_IS_THREAD(h_obj)) {
26774 hdr_size = (duk_small_uint_t) sizeof(duk_hthread);
11fdf7f2
TL
26775#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
26776 } else if (DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) {
26777 hdr_size = (duk_small_uint_t) sizeof(duk_hbufferobject);
26778#endif
7c673cae
FG
26779 } else {
26780 hdr_size = (duk_small_uint_t) sizeof(duk_hobject);
26781 }
26782 duk_push_uint(ctx, (duk_uint_t) hdr_size);
11fdf7f2 26783 duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_P_ALLOC_SIZE(h_obj));
7c673cae
FG
26784 duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_ESIZE(h_obj));
26785 /* Note: e_next indicates the number of gc-reachable entries
26786 * in the entry part, and also indicates the index where the
26787 * next new property would be inserted. It does *not* indicate
26788 * the number of non-NULL keys present in the object. That
26789 * value could be counted separately but requires a pass through
26790 * the key list.
26791 */
26792 duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_ENEXT(h_obj));
26793 duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_ASIZE(h_obj));
26794 duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_HSIZE(h_obj));
26795 if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h_obj)) {
26796 duk_hbuffer *h_data = (duk_hbuffer *) DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, (duk_hcompiledfunction *) h_obj);
26797 if (h_data) {
26798 duk_push_uint(ctx, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_data));
26799 } else {
26800 duk_push_uint(ctx, 0);
26801 }
26802 }
26803 break;
26804 }
26805 case DUK_HTYPE_BUFFER: {
26806 duk_hbuffer *h_buf = (duk_hbuffer *) h;
26807 if (DUK_HBUFFER_HAS_DYNAMIC(h_buf)) {
26808 if (DUK_HBUFFER_HAS_EXTERNAL(h_buf)) {
26809 duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hbuffer_external)));
26810 } else {
26811 /* When alloc_size == 0 the second allocation may not
26812 * actually exist.
26813 */
26814 duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hbuffer_dynamic)));
26815 }
26816 duk_push_uint(ctx, (duk_uint_t) (DUK_HBUFFER_GET_SIZE(h_buf)));
26817 } else {
26818 duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hbuffer_fixed) + DUK_HBUFFER_GET_SIZE(h_buf) + 1));
26819 }
26820 break;
26821
26822 }
26823 }
26824
26825 done:
26826 /* set values into ret array */
26827 /* XXX: primitive to make array from valstack slice */
26828 n = duk_get_top(ctx);
26829 for (i = 2; i < n; i++) {
26830 duk_dup(ctx, i);
26831 duk_put_prop_index(ctx, 1, i - 2);
26832 }
26833 duk_dup(ctx, 1);
26834 return 1;
26835}
26836
26837DUK_INTERNAL duk_ret_t duk_bi_duktape_object_act(duk_context *ctx) {
26838 duk_hthread *thr = (duk_hthread *) ctx;
26839 duk_activation *act;
26840 duk_uint_fast32_t pc;
26841 duk_uint_fast32_t line;
26842 duk_int_t level;
26843
26844 /* -1 = top callstack entry, callstack[callstack_top - 1]
26845 * -callstack_top = bottom callstack entry, callstack[0]
26846 */
26847 level = duk_to_int(ctx, 0);
26848 if (level >= 0 || -level > (duk_int_t) thr->callstack_top) {
26849 return 0;
26850 }
26851 DUK_ASSERT(level >= -((duk_int_t) thr->callstack_top) && level <= -1);
26852 act = thr->callstack + thr->callstack_top + level;
26853
26854 duk_push_object(ctx);
26855
26856 duk_push_tval(ctx, &act->tv_func);
26857
26858 /* Relevant PC is just before current one because PC is
26859 * post-incremented. This should match what error augment
26860 * code does.
26861 */
26862 pc = duk_hthread_get_act_prev_pc(thr, act);
26863 duk_push_uint(ctx, (duk_uint_t) pc);
26864
26865#if defined(DUK_USE_PC2LINE)
26866 line = duk_hobject_pc2line_query(ctx, -2, pc);
26867#else
26868 line = 0;
26869#endif
26870 duk_push_uint(ctx, (duk_uint_t) line);
26871
26872 /* Providing access to e.g. act->lex_env would be dangerous: these
26873 * internal structures must never be accessible to the application.
26874 * Duktape relies on them having consistent data, and this consistency
26875 * is only asserted for, not checked for.
26876 */
26877
26878 /* [ level obj func pc line ] */
26879
26880 /* XXX: version specific array format instead? */
26881 duk_xdef_prop_stridx_wec(ctx, -4, DUK_STRIDX_LINE_NUMBER);
26882 duk_xdef_prop_stridx_wec(ctx, -3, DUK_STRIDX_PC);
26883 duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_LC_FUNCTION);
26884 return 1;
26885}
26886
26887DUK_INTERNAL duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx) {
26888#ifdef DUK_USE_MARK_AND_SWEEP
26889 duk_hthread *thr = (duk_hthread *) ctx;
26890 duk_small_uint_t flags;
26891 duk_bool_t rc;
26892
26893 flags = (duk_small_uint_t) duk_get_uint(ctx, 0);
26894 rc = duk_heap_mark_and_sweep(thr->heap, flags);
26895
26896 /* XXX: Not sure what the best return value would be in the API.
26897 * Return a boolean for now. Note that rc == 0 is success (true).
26898 */
26899 duk_push_boolean(ctx, !rc);
26900 return 1;
26901#else
26902 DUK_UNREF(ctx);
26903 return 0;
26904#endif
26905}
26906
26907DUK_INTERNAL duk_ret_t duk_bi_duktape_object_fin(duk_context *ctx) {
26908 (void) duk_require_hobject(ctx, 0);
26909 if (duk_get_top(ctx) >= 2) {
26910 /* Set: currently a finalizer is disabled by setting it to
26911 * undefined; this does not remove the property at the moment.
26912 * The value could be type checked to be either a function
26913 * or something else; if something else, the property could
26914 * be deleted.
26915 */
26916 duk_set_top(ctx, 2);
26917 (void) duk_put_prop_stridx(ctx, 0, DUK_STRIDX_INT_FINALIZER);
26918 return 0;
26919 } else {
26920 /* Get. */
26921 DUK_ASSERT(duk_get_top(ctx) == 1);
26922 duk_get_prop_stridx(ctx, 0, DUK_STRIDX_INT_FINALIZER);
26923 return 1;
26924 }
26925}
26926
26927DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx) {
26928 duk_hthread *thr = (duk_hthread *) ctx;
26929 duk_hstring *h_str;
26930
11fdf7f2
TL
26931 DUK_UNREF(thr);
26932
7c673cae
FG
26933 /* Vararg function: must be careful to check/require arguments.
26934 * The JSON helpers accept invalid indices and treat them like
26935 * non-existent optional parameters.
26936 */
26937
26938 h_str = duk_require_hstring(ctx, 0);
26939 duk_require_valid_index(ctx, 1);
26940
26941 if (h_str == DUK_HTHREAD_STRING_HEX(thr)) {
26942 duk_set_top(ctx, 2);
26943 duk_hex_encode(ctx, 1);
26944 DUK_ASSERT_TOP(ctx, 2);
26945 } else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) {
26946 duk_set_top(ctx, 2);
26947 duk_base64_encode(ctx, 1);
26948 DUK_ASSERT_TOP(ctx, 2);
26949#ifdef DUK_USE_JX
26950 } else if (h_str == DUK_HTHREAD_STRING_JX(thr)) {
26951 duk_bi_json_stringify_helper(ctx,
26952 1 /*idx_value*/,
26953 2 /*idx_replacer*/,
26954 3 /*idx_space*/,
26955 DUK_JSON_FLAG_EXT_CUSTOM |
26956 DUK_JSON_FLAG_ASCII_ONLY |
26957 DUK_JSON_FLAG_AVOID_KEY_QUOTES /*flags*/);
26958#endif
26959#ifdef DUK_USE_JC
26960 } else if (h_str == DUK_HTHREAD_STRING_JC(thr)) {
26961 duk_bi_json_stringify_helper(ctx,
26962 1 /*idx_value*/,
26963 2 /*idx_replacer*/,
26964 3 /*idx_space*/,
26965 DUK_JSON_FLAG_EXT_COMPATIBLE |
26966 DUK_JSON_FLAG_ASCII_ONLY /*flags*/);
26967#endif
26968 } else {
26969 return DUK_RET_TYPE_ERROR;
26970 }
26971 return 1;
26972}
26973
26974DUK_INTERNAL duk_ret_t duk_bi_duktape_object_dec(duk_context *ctx) {
26975 duk_hthread *thr = (duk_hthread *) ctx;
26976 duk_hstring *h_str;
26977
11fdf7f2
TL
26978 DUK_UNREF(thr);
26979
7c673cae
FG
26980 /* Vararg function: must be careful to check/require arguments.
26981 * The JSON helpers accept invalid indices and treat them like
26982 * non-existent optional parameters.
26983 */
26984
26985 h_str = duk_require_hstring(ctx, 0);
26986 duk_require_valid_index(ctx, 1);
26987
26988 if (h_str == DUK_HTHREAD_STRING_HEX(thr)) {
26989 duk_set_top(ctx, 2);
26990 duk_hex_decode(ctx, 1);
26991 DUK_ASSERT_TOP(ctx, 2);
26992 } else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) {
26993 duk_set_top(ctx, 2);
26994 duk_base64_decode(ctx, 1);
26995 DUK_ASSERT_TOP(ctx, 2);
26996#ifdef DUK_USE_JX
26997 } else if (h_str == DUK_HTHREAD_STRING_JX(thr)) {
26998 duk_bi_json_parse_helper(ctx,
26999 1 /*idx_value*/,
27000 2 /*idx_replacer*/,
27001 DUK_JSON_FLAG_EXT_CUSTOM /*flags*/);
27002#endif
27003#ifdef DUK_USE_JC
27004 } else if (h_str == DUK_HTHREAD_STRING_JC(thr)) {
27005 duk_bi_json_parse_helper(ctx,
27006 1 /*idx_value*/,
27007 2 /*idx_replacer*/,
27008 DUK_JSON_FLAG_EXT_COMPATIBLE /*flags*/);
27009#endif
27010 } else {
27011 return DUK_RET_TYPE_ERROR;
27012 }
27013 return 1;
27014}
27015
27016/*
27017 * Compact an object
27018 */
27019
27020DUK_INTERNAL duk_ret_t duk_bi_duktape_object_compact(duk_context *ctx) {
27021 DUK_ASSERT_TOP(ctx, 1);
27022 duk_compact(ctx, 0);
27023 return 1; /* return the argument object */
27024}
7c673cae
FG
27025/*
27026 * Error built-ins
27027 */
27028
27029/* include removed: duk_internal.h */
27030
27031DUK_INTERNAL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx) {
27032 /* Behavior for constructor and non-constructor call is
27033 * the same except for augmenting the created error. When
27034 * called as a constructor, the caller (duk_new()) will handle
27035 * augmentation; when called as normal function, we need to do
27036 * it here.
27037 */
27038
27039 duk_hthread *thr = (duk_hthread *) ctx;
27040 duk_small_int_t bidx_prototype = duk_get_current_magic(ctx);
27041
27042 /* same for both error and each subclass like TypeError */
27043 duk_uint_t flags_and_class = DUK_HOBJECT_FLAG_EXTENSIBLE |
27044 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR);
27045
27046 DUK_UNREF(thr);
27047
27048 duk_push_object_helper(ctx, flags_and_class, bidx_prototype);
27049
27050 /* If message is undefined, the own property 'message' is not set at
27051 * all to save property space. An empty message is inherited anyway.
27052 */
27053 if (!duk_is_undefined(ctx, 0)) {
27054 duk_to_string(ctx, 0);
27055 duk_dup(ctx, 0); /* [ message error message ] */
27056 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
27057 }
27058
27059 /* Augment the error if called as a normal function. __FILE__ and __LINE__
27060 * are not desirable in this case.
27061 */
27062
27063#ifdef DUK_USE_AUGMENT_ERROR_CREATE
27064 if (!duk_is_constructor_call(ctx)) {
27065 duk_err_augment_error_create(thr, thr, NULL, 0, 1 /*noblame_fileline*/);
27066 }
27067#endif
27068
27069 return 1;
27070}
27071
27072DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx) {
27073 /* XXX: optimize with more direct internal access */
27074
27075 duk_push_this(ctx);
27076 (void) duk_require_hobject_or_lfunc_coerce(ctx, -1);
27077
27078 /* [ ... this ] */
27079
27080 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME);
27081 if (duk_is_undefined(ctx, -1)) {
27082 duk_pop(ctx);
27083 duk_push_string(ctx, "Error");
27084 } else {
27085 duk_to_string(ctx, -1);
27086 }
27087
27088 /* [ ... this name ] */
27089
27090 /* XXX: Are steps 6 and 7 in E5 Section 15.11.4.4 duplicated by
27091 * accident or are they actually needed? The first ToString()
27092 * could conceivably return 'undefined'.
27093 */
27094 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE);
27095 if (duk_is_undefined(ctx, -1)) {
27096 duk_pop(ctx);
27097 duk_push_string(ctx, "");
27098 } else {
27099 duk_to_string(ctx, -1);
27100 }
27101
27102 /* [ ... this name message ] */
27103
27104 if (duk_get_length(ctx, -2) == 0) {
27105 /* name is empty -> return message */
27106 return 1;
27107 }
27108 if (duk_get_length(ctx, -1) == 0) {
27109 /* message is empty -> return name */
27110 duk_pop(ctx);
27111 return 1;
27112 }
27113 duk_push_string(ctx, ": ");
27114 duk_insert(ctx, -2); /* ... name ': ' message */
27115 duk_concat(ctx, 3);
27116
27117 return 1;
27118}
27119
11fdf7f2 27120#if defined(DUK_USE_TRACEBACKS)
7c673cae
FG
27121
27122/*
27123 * Traceback handling
27124 *
27125 * The unified helper decodes the traceback and produces various requested
27126 * outputs. It should be optimized for size, and may leave garbage on stack,
27127 * only the topmost return value matters. For instance, traceback separator
27128 * and decoded strings are pushed even when looking for filename only.
27129 *
27130 * NOTE: although _Tracedata is an internal property, user code can currently
27131 * write to the array (or replace it with something other than an array).
27132 * The code below must tolerate arbitrary _Tracedata. It can throw errors
27133 * etc, but cannot cause a segfault or memory unsafe behavior.
27134 */
27135
27136/* constants arbitrary, chosen for small loads */
27137#define DUK__OUTPUT_TYPE_TRACEBACK (-1)
27138#define DUK__OUTPUT_TYPE_FILENAME 0
27139#define DUK__OUTPUT_TYPE_LINENUMBER 1
27140
11fdf7f2 27141DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t output_type) {
7c673cae
FG
27142 duk_hthread *thr = (duk_hthread *) ctx;
27143 duk_idx_t idx_td;
27144 duk_small_int_t i; /* traceback depth fits into 16 bits */
27145 duk_small_int_t t; /* stack type fits into 16 bits */
11fdf7f2
TL
27146 duk_small_int_t count_func = 0; /* traceback depth ensures fits into 16 bits */
27147 const char *str_tailcall = " tailcall";
7c673cae
FG
27148 const char *str_strict = " strict";
27149 const char *str_construct = " construct";
27150 const char *str_prevyield = " preventsyield";
27151 const char *str_directeval = " directeval";
27152 const char *str_empty = "";
27153
27154 DUK_ASSERT_TOP(ctx, 0); /* fixed arg count */
11fdf7f2 27155 DUK_UNREF(thr);
7c673cae
FG
27156
27157 duk_push_this(ctx);
27158 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TRACEDATA);
27159 idx_td = duk_get_top_index(ctx);
27160
11fdf7f2 27161 duk_push_hstring_stridx(ctx, DUK_STRIDX_NEWLINE_4SPACE);
7c673cae
FG
27162 duk_push_this(ctx);
27163
27164 /* [ ... this tracedata sep this ] */
27165
27166 /* XXX: skip null filename? */
27167
27168 if (duk_check_type(ctx, idx_td, DUK_TYPE_OBJECT)) {
27169 /* Current tracedata contains 2 entries per callstack entry. */
27170 for (i = 0; ; i += 2) {
27171 duk_int_t pc;
27172 duk_int_t line;
27173 duk_int_t flags;
27174 duk_double_t d;
27175 const char *funcname;
27176 const char *filename;
27177 duk_hobject *h_func;
27178 duk_hstring *h_name;
27179
27180 duk_require_stack(ctx, 5);
27181 duk_get_prop_index(ctx, idx_td, i);
27182 duk_get_prop_index(ctx, idx_td, i + 1);
27183 d = duk_to_number(ctx, -1);
27184 pc = (duk_int_t) DUK_FMOD(d, DUK_DOUBLE_2TO32);
27185 flags = (duk_int_t) DUK_FLOOR(d / DUK_DOUBLE_2TO32);
27186 t = (duk_small_int_t) duk_get_type(ctx, -2);
27187
27188 if (t == DUK_TYPE_OBJECT || t == DUK_TYPE_LIGHTFUNC) {
27189 /*
27190 * Ecmascript/native function call or lightfunc call
27191 */
27192
11fdf7f2
TL
27193 count_func++;
27194
7c673cae
FG
27195 /* [ ... v1(func) v2(pc+flags) ] */
27196
27197 h_func = duk_get_hobject(ctx, -2); /* NULL for lightfunc */
27198
27199 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME);
27200 duk_get_prop_stridx(ctx, -3, DUK_STRIDX_FILE_NAME);
27201
27202#if defined(DUK_USE_PC2LINE)
27203 line = duk_hobject_pc2line_query(ctx, -4, (duk_uint_fast32_t) pc);
27204#else
27205 line = 0;
27206#endif
27207
27208 /* [ ... v1 v2 name filename ] */
27209
11fdf7f2
TL
27210 /* When looking for .fileName/.lineNumber, blame first
27211 * function which has a .fileName.
27212 */
27213 if (duk_is_string(ctx, -1)) {
27214 if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
27215 return 1;
27216 } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
27217 duk_push_int(ctx, line);
27218 return 1;
27219 }
7c673cae
FG
27220 }
27221
11fdf7f2
TL
27222 /* XXX: Change 'anon' handling here too, to use empty string for anonymous functions? */
27223 /* XXX: Could be improved by coercing to a readable duk_tval (especially string escaping) */
7c673cae
FG
27224 h_name = duk_get_hstring(ctx, -2); /* may be NULL */
27225 funcname = (h_name == NULL || h_name == DUK_HTHREAD_STRING_EMPTY_STRING(thr)) ?
11fdf7f2 27226 "[anon]" : (const char *) DUK_HSTRING_GET_DATA(h_name);
7c673cae
FG
27227 filename = duk_get_string(ctx, -1);
27228 filename = filename ? filename : "";
27229 DUK_ASSERT(funcname != NULL);
27230 DUK_ASSERT(filename != NULL);
27231
27232 if (h_func == NULL) {
11fdf7f2 27233 duk_push_sprintf(ctx, "at %s light%s%s%s%s%s",
7c673cae
FG
27234 (const char *) funcname,
27235 (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
11fdf7f2 27236 (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
7c673cae
FG
27237 (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
27238 (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
27239 (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
27240 } else if (DUK_HOBJECT_HAS_NATIVEFUNCTION(h_func)) {
11fdf7f2 27241 duk_push_sprintf(ctx, "at %s (%s) native%s%s%s%s%s",
7c673cae
FG
27242 (const char *) funcname,
27243 (const char *) filename,
27244 (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
11fdf7f2 27245 (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
7c673cae
FG
27246 (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
27247 (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
27248 (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
27249 } else {
11fdf7f2 27250 duk_push_sprintf(ctx, "at %s (%s:%ld)%s%s%s%s%s",
7c673cae
FG
27251 (const char *) funcname,
27252 (const char *) filename,
27253 (long) line,
27254 (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
11fdf7f2 27255 (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
7c673cae
FG
27256 (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
27257 (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
27258 (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
27259 }
27260 duk_replace(ctx, -5); /* [ ... v1 v2 name filename str ] -> [ ... str v2 name filename ] */
27261 duk_pop_n(ctx, 3); /* -> [ ... str ] */
27262 } else if (t == DUK_TYPE_STRING) {
27263 /*
27264 * __FILE__ / __LINE__ entry, here 'pc' is line number directly.
27265 * Sometimes __FILE__ / __LINE__ is reported as the source for
27266 * the error (fileName, lineNumber), sometimes not.
27267 */
27268
27269 /* [ ... v1(filename) v2(line+flags) ] */
27270
11fdf7f2
TL
27271 /* When looking for .fileName/.lineNumber, blame compilation
27272 * or C call site unless flagged not to do so.
27273 */
7c673cae
FG
27274 if (!(flags & DUK_TB_FLAG_NOBLAME_FILELINE)) {
27275 if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
27276 duk_pop(ctx);
27277 return 1;
27278 } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
27279 duk_push_int(ctx, pc);
27280 return 1;
27281 }
27282 }
27283
11fdf7f2 27284 duk_push_sprintf(ctx, "at [anon] (%s:%ld) internal",
7c673cae
FG
27285 (const char *) duk_get_string(ctx, -2), (long) pc);
27286 duk_replace(ctx, -3); /* [ ... v1 v2 str ] -> [ ... str v2 ] */
27287 duk_pop(ctx); /* -> [ ... str ] */
27288 } else {
27289 /* unknown, ignore */
27290 duk_pop_2(ctx);
27291 break;
27292 }
27293 }
27294
11fdf7f2 27295 if (count_func >= DUK_USE_TRACEBACK_DEPTH) {
7c673cae
FG
27296 /* Possibly truncated; there is no explicit truncation
27297 * marker so this is the best we can do.
27298 */
27299
27300 duk_push_hstring_stridx(ctx, DUK_STRIDX_BRACKETED_ELLIPSIS);
27301 }
27302 }
27303
27304 /* [ ... this tracedata sep this str1 ... strN ] */
27305
27306 if (output_type != DUK__OUTPUT_TYPE_TRACEBACK) {
27307 return 0;
27308 } else {
27309 /* The 'this' after 'sep' will get ToString() coerced by
27310 * duk_join() automatically. We don't want to do that
27311 * coercion when providing .fileName or .lineNumber (GH-254).
27312 */
27313 duk_join(ctx, duk_get_top(ctx) - (idx_td + 2) /*count, not including sep*/);
27314 return 1;
27315 }
27316}
27317
11fdf7f2
TL
27318/* XXX: Output type could be encoded into native function 'magic' value to
27319 * save space. For setters the stridx could be encoded into 'magic'.
7c673cae
FG
27320 */
27321
27322DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx) {
11fdf7f2 27323 return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_TRACEBACK);
7c673cae
FG
27324}
27325
27326DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx) {
11fdf7f2 27327 return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_FILENAME);
7c673cae
FG
27328}
27329
27330DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx) {
11fdf7f2 27331 return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_LINENUMBER);
7c673cae
FG
27332}
27333
27334#undef DUK__OUTPUT_TYPE_TRACEBACK
27335#undef DUK__OUTPUT_TYPE_FILENAME
27336#undef DUK__OUTPUT_TYPE_LINENUMBER
27337
27338#else /* DUK_USE_TRACEBACKS */
27339
27340/*
27341 * Traceback handling when tracebacks disabled.
27342 *
27343 * The fileName / lineNumber stubs are now necessary because built-in
27344 * data will include the accessor properties in Error.prototype. If those
27345 * are removed for builds without tracebacks, these can also be removed.
27346 * 'stack' should still be present and produce a ToString() equivalent:
27347 * this is useful for user code which prints a stacktrace and expects to
27348 * see something useful. A normal stacktrace also begins with a ToString()
27349 * of the error so this makes sense.
27350 */
27351
27352DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx) {
27353 /* XXX: remove this native function and map 'stack' accessor
27354 * to the toString() implementation directly.
27355 */
27356 return duk_bi_error_prototype_to_string(ctx);
27357}
27358
27359DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx) {
27360 DUK_UNREF(ctx);
27361 return 0;
27362}
27363
27364DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx) {
27365 DUK_UNREF(ctx);
27366 return 0;
27367}
27368
27369#endif /* DUK_USE_TRACEBACKS */
27370
11fdf7f2
TL
27371DUK_LOCAL duk_ret_t duk__error_setter_helper(duk_context *ctx, duk_small_uint_t stridx_key) {
27372 /* Attempt to write 'stack', 'fileName', 'lineNumber' works as if
27373 * user code called Object.defineProperty() to create an overriding
27374 * own property. This allows user code to overwrite .fileName etc
27375 * intuitively as e.g. "err.fileName = 'dummy'" as one might expect.
27376 * See https://github.com/svaarala/duktape/issues/387.
7c673cae 27377 */
11fdf7f2
TL
27378
27379 DUK_ASSERT_TOP(ctx, 1); /* fixed arg count: value */
27380
27381 duk_push_this(ctx);
27382 duk_push_hstring_stridx(ctx, (duk_small_int_t) stridx_key);
27383 duk_dup(ctx, 0);
27384
27385 /* [ ... obj key value ] */
27386
27387 DUK_DD(DUK_DDPRINT("error setter: %!T %!T %!T",
27388 duk_get_tval(ctx, -3), duk_get_tval(ctx, -2), duk_get_tval(ctx, -1)));
27389
27390 duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE |
27391 DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE |
27392 DUK_DEFPROP_HAVE_ENUMERABLE | /*not enumerable*/
27393 DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE);
7c673cae
FG
27394 return 0;
27395}
11fdf7f2
TL
27396
27397DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_setter(duk_context *ctx) {
27398 return duk__error_setter_helper(ctx, DUK_STRIDX_STACK);
27399}
27400
27401DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_setter(duk_context *ctx) {
27402 return duk__error_setter_helper(ctx, DUK_STRIDX_FILE_NAME);
27403}
27404
27405DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_context *ctx) {
27406 return duk__error_setter_helper(ctx, DUK_STRIDX_LINE_NUMBER);
27407}
7c673cae
FG
27408/*
27409 * Function built-ins
27410 */
27411
27412/* include removed: duk_internal.h */
27413
27414DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_context *ctx) {
27415 duk_hthread *thr = (duk_hthread *) ctx;
27416 duk_hstring *h_sourcecode;
27417 duk_idx_t nargs;
27418 duk_idx_t i;
27419 duk_small_uint_t comp_flags;
27420 duk_hcompiledfunction *func;
27421 duk_hobject *outer_lex_env;
27422 duk_hobject *outer_var_env;
27423
27424 /* normal and constructor calls have identical semantics */
27425
27426 nargs = duk_get_top(ctx);
27427 for (i = 0; i < nargs; i++) {
27428 duk_to_string(ctx, i);
27429 }
27430
27431 if (nargs == 0) {
27432 duk_push_string(ctx, "");
27433 duk_push_string(ctx, "");
27434 } else if (nargs == 1) {
27435 /* XXX: cover this with the generic >1 case? */
27436 duk_push_string(ctx, "");
27437 } else {
27438 duk_insert(ctx, 0); /* [ arg1 ... argN-1 body] -> [body arg1 ... argN-1] */
27439 duk_push_string(ctx, ",");
27440 duk_insert(ctx, 1);
27441 duk_join(ctx, nargs - 1);
27442 }
27443
27444 /* [ body formals ], formals is comma separated list that needs to be parsed */
27445
27446 DUK_ASSERT_TOP(ctx, 2);
27447
27448 /* XXX: this placeholder is not always correct, but use for now.
27449 * It will fail in corner cases; see test-dev-func-cons-args.js.
27450 */
27451 duk_push_string(ctx, "function(");
27452 duk_dup(ctx, 1);
27453 duk_push_string(ctx, "){");
27454 duk_dup(ctx, 0);
27455 duk_push_string(ctx, "}");
27456 duk_concat(ctx, 5);
27457
27458 /* [ body formals source ] */
27459
27460 DUK_ASSERT_TOP(ctx, 3);
27461
27462 /* strictness is not inherited, intentional */
27463 comp_flags = DUK_JS_COMPILE_FLAG_FUNCEXPR;
27464
27465 duk_push_hstring_stridx(ctx, DUK_STRIDX_COMPILE); /* XXX: copy from caller? */ /* XXX: ignored now */
27466 h_sourcecode = duk_require_hstring(ctx, -2);
27467 duk_js_compile(thr,
27468 (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode),
27469 (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode),
27470 comp_flags);
27471 func = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);
27472 DUK_ASSERT(func != NULL);
27473 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) func));
27474
27475 /* [ body formals source template ] */
27476
27477 /* only outer_lex_env matters, as functions always get a new
27478 * variable declaration environment.
27479 */
27480
27481 outer_lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
27482 outer_var_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
27483
11fdf7f2 27484 duk_js_push_closure(thr, func, outer_var_env, outer_lex_env, 1 /*add_auto_proto*/);
7c673cae
FG
27485
27486 /* [ body formals source template closure ] */
27487
27488 return 1;
27489}
27490
27491DUK_INTERNAL duk_ret_t duk_bi_function_prototype(duk_context *ctx) {
27492 /* ignore arguments, return undefined (E5 Section 15.3.4) */
27493 DUK_UNREF(ctx);
27494 return 0;
27495}
27496
27497DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx) {
27498 duk_tval *tv;
27499
27500 /*
27501 * E5 Section 15.3.4.2 places few requirements on the output of
27502 * this function:
27503 *
27504 * - The result is an implementation dependent representation
27505 * of the function; in particular
27506 *
27507 * - The result must follow the syntax of a FunctionDeclaration.
27508 * In particular, the function must have a name (even in the
27509 * case of an anonymous function or a function with an empty
27510 * name).
27511 *
27512 * - Note in particular that the output does NOT need to compile
27513 * into anything useful.
27514 */
27515
27516
27517 /* XXX: faster internal way to get this */
27518 duk_push_this(ctx);
27519 tv = duk_get_tval(ctx, -1);
27520 DUK_ASSERT(tv != NULL);
27521
27522 if (DUK_TVAL_IS_OBJECT(tv)) {
27523 duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv);
11fdf7f2 27524 const char *func_name;
7c673cae 27525
11fdf7f2
TL
27526 /* Function name: missing/undefined is mapped to empty string,
27527 * otherwise coerce to string.
27528 */
27529 /* XXX: currently no handling for non-allowed identifier characters,
27530 * e.g. a '{' in the function name.
7c673cae 27531 */
7c673cae 27532 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME);
11fdf7f2
TL
27533 if (duk_is_undefined(ctx, -1)) {
27534 func_name = "";
27535 } else {
7c673cae
FG
27536 func_name = duk_to_string(ctx, -1);
27537 DUK_ASSERT(func_name != NULL);
7c673cae
FG
27538 }
27539
11fdf7f2
TL
27540 /* Indicate function type in the function body using a dummy
27541 * directive.
27542 */
7c673cae 27543 if (DUK_HOBJECT_HAS_COMPILEDFUNCTION(obj)) {
11fdf7f2 27544 duk_push_sprintf(ctx, "function %s() {\"ecmascript\"}", (const char *) func_name);
7c673cae 27545 } else if (DUK_HOBJECT_HAS_NATIVEFUNCTION(obj)) {
11fdf7f2 27546 duk_push_sprintf(ctx, "function %s() {\"native\"}", (const char *) func_name);
7c673cae 27547 } else if (DUK_HOBJECT_HAS_BOUND(obj)) {
11fdf7f2 27548 duk_push_sprintf(ctx, "function %s() {\"bound\"}", (const char *) func_name);
7c673cae
FG
27549 } else {
27550 goto type_error;
27551 }
27552 } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
27553 duk_push_lightfunc_tostring(ctx, tv);
27554 } else {
27555 goto type_error;
27556 }
27557
27558 return 1;
27559
27560 type_error:
27561 return DUK_RET_TYPE_ERROR;
27562}
27563
27564DUK_INTERNAL duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx) {
27565 duk_idx_t len;
27566 duk_idx_t i;
27567
27568 DUK_ASSERT_TOP(ctx, 2); /* not a vararg function */
27569
27570 duk_push_this(ctx);
27571 if (!duk_is_callable(ctx, -1)) {
27572 DUK_DDD(DUK_DDDPRINT("func is not callable"));
27573 goto type_error;
27574 }
27575 duk_insert(ctx, 0);
27576 DUK_ASSERT_TOP(ctx, 3);
27577
27578 DUK_DDD(DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argArray=%!iT",
27579 (duk_tval *) duk_get_tval(ctx, 0),
27580 (duk_tval *) duk_get_tval(ctx, 1),
27581 (duk_tval *) duk_get_tval(ctx, 2)));
27582
27583 /* [ func thisArg argArray ] */
27584
27585 if (duk_is_null_or_undefined(ctx, 2)) {
27586 DUK_DDD(DUK_DDDPRINT("argArray is null/undefined, no args"));
27587 len = 0;
27588 } else if (!duk_is_object(ctx, 2)) {
27589 goto type_error;
27590 } else {
27591 DUK_DDD(DUK_DDDPRINT("argArray is an object"));
27592
27593 /* XXX: make this an internal helper */
27594 duk_get_prop_stridx(ctx, 2, DUK_STRIDX_LENGTH);
27595 len = (duk_idx_t) duk_to_uint32(ctx, -1); /* ToUint32() coercion required */
27596 duk_pop(ctx);
27597
27598 duk_require_stack(ctx, len);
27599
27600 DUK_DDD(DUK_DDDPRINT("argArray length is %ld", (long) len));
27601 for (i = 0; i < len; i++) {
27602 duk_get_prop_index(ctx, 2, i);
27603 }
27604 }
27605 duk_remove(ctx, 2);
27606 DUK_ASSERT_TOP(ctx, 2 + len);
27607
27608 /* [ func thisArg arg1 ... argN ] */
27609
27610 DUK_DDD(DUK_DDDPRINT("apply, func=%!iT, thisArg=%!iT, len=%ld",
27611 (duk_tval *) duk_get_tval(ctx, 0),
27612 (duk_tval *) duk_get_tval(ctx, 1),
27613 (long) len));
27614 duk_call_method(ctx, len);
27615 return 1;
27616
27617 type_error:
27618 return DUK_RET_TYPE_ERROR;
27619}
27620
27621DUK_INTERNAL duk_ret_t duk_bi_function_prototype_call(duk_context *ctx) {
27622 duk_idx_t nargs;
27623
27624 /* Step 1 is not necessary because duk_call_method() will take
27625 * care of it.
27626 */
27627
27628 /* vararg function, thisArg needs special handling */
27629 nargs = duk_get_top(ctx); /* = 1 + arg count */
27630 if (nargs == 0) {
27631 duk_push_undefined(ctx);
27632 nargs++;
27633 }
27634 DUK_ASSERT(nargs >= 1);
27635
27636 /* [ thisArg arg1 ... argN ] */
27637
27638 duk_push_this(ctx); /* 'func' in the algorithm */
27639 duk_insert(ctx, 0);
27640
27641 /* [ func thisArg arg1 ... argN ] */
27642
27643 DUK_DDD(DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argcount=%ld, top=%ld",
27644 (duk_tval *) duk_get_tval(ctx, 0),
27645 (duk_tval *) duk_get_tval(ctx, 1),
27646 (long) (nargs - 1),
27647 (long) duk_get_top(ctx)));
27648 duk_call_method(ctx, nargs - 1);
27649 return 1;
27650}
27651
27652/* XXX: the implementation now assumes "chained" bound functions,
27653 * whereas "collapsed" bound functions (where there is ever only
27654 * one bound function which directly points to a non-bound, final
27655 * function) would require a "collapsing" implementation which
27656 * merges argument lists etc here.
27657 */
27658DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx) {
27659 duk_hobject *h_bound;
27660 duk_hobject *h_target;
27661 duk_idx_t nargs;
27662 duk_idx_t i;
27663
27664 /* vararg function, careful arg handling (e.g. thisArg may not be present) */
27665 nargs = duk_get_top(ctx); /* = 1 + arg count */
27666 if (nargs == 0) {
27667 duk_push_undefined(ctx);
27668 nargs++;
27669 }
27670 DUK_ASSERT(nargs >= 1);
27671
27672 duk_push_this(ctx);
27673 if (!duk_is_callable(ctx, -1)) {
27674 DUK_DDD(DUK_DDDPRINT("func is not callable"));
27675 goto type_error;
27676 }
27677
27678 /* [ thisArg arg1 ... argN func ] (thisArg+args == nargs total) */
27679 DUK_ASSERT_TOP(ctx, nargs + 1);
27680
27681 /* create bound function object */
27682 duk_push_object_helper(ctx,
27683 DUK_HOBJECT_FLAG_EXTENSIBLE |
27684 DUK_HOBJECT_FLAG_BOUND |
27685 DUK_HOBJECT_FLAG_CONSTRUCTABLE |
27686 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION),
27687 DUK_BIDX_FUNCTION_PROTOTYPE);
27688 h_bound = duk_get_hobject(ctx, -1);
27689 DUK_ASSERT(h_bound != NULL);
27690
27691 /* [ thisArg arg1 ... argN func boundFunc ] */
27692 duk_dup(ctx, -2); /* func */
27693 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
27694
27695 duk_dup(ctx, 0); /* thisArg */
27696 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE);
27697
27698 duk_push_array(ctx);
27699
27700 /* [ thisArg arg1 ... argN func boundFunc argArray ] */
27701
27702 for (i = 0; i < nargs - 1; i++) {
27703 duk_dup(ctx, 1 + i);
27704 duk_put_prop_index(ctx, -2, i);
27705 }
27706 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_ARGS, DUK_PROPDESC_FLAGS_NONE);
27707
27708 /* [ thisArg arg1 ... argN func boundFunc ] */
27709
27710 /* bound function 'length' property is interesting */
27711 h_target = duk_get_hobject(ctx, -2);
27712 if (h_target == NULL || /* lightfunc */
27713 DUK_HOBJECT_GET_CLASS_NUMBER(h_target) == DUK_HOBJECT_CLASS_FUNCTION) {
27714 /* For lightfuncs, simply read the virtual property. */
27715 duk_int_t tmp;
27716 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH);
27717 tmp = duk_to_int(ctx, -1) - (nargs - 1); /* step 15.a */
27718 duk_pop(ctx);
27719 duk_push_int(ctx, (tmp < 0 ? 0 : tmp));
27720 } else {
27721 duk_push_int(ctx, 0);
27722 }
27723 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE); /* attrs in E5 Section 15.3.5.1 */
27724
27725 /* caller and arguments must use the same thrower, [[ThrowTypeError]] */
27726 duk_xdef_prop_stridx_thrower(ctx, -1, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
27727 duk_xdef_prop_stridx_thrower(ctx, -1, DUK_STRIDX_LC_ARGUMENTS, DUK_PROPDESC_FLAGS_NONE);
27728
27729 /* these non-standard properties are copied for convenience */
27730 /* XXX: 'copy properties' API call? */
27731 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME);
27732 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_WC);
27733 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME);
27734 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC);
27735
27736 /* The 'strict' flag is copied to get the special [[Get]] of E5.1
27737 * Section 15.3.5.4 to apply when a 'caller' value is a strict bound
27738 * function. Not sure if this is correct, because the specification
27739 * is a bit ambiguous on this point but it would make sense.
27740 */
27741 if (h_target == NULL) {
27742 /* Lightfuncs are always strict. */
27743 DUK_HOBJECT_SET_STRICT(h_bound);
27744 } else if (DUK_HOBJECT_HAS_STRICT(h_target)) {
27745 DUK_HOBJECT_SET_STRICT(h_bound);
27746 }
27747 DUK_DDD(DUK_DDDPRINT("created bound function: %!iT", (duk_tval *) duk_get_tval(ctx, -1)));
27748
27749 return 1;
27750
27751 type_error:
27752 return DUK_RET_TYPE_ERROR;
27753}
7c673cae
FG
27754/*
27755 * Global object built-ins
27756 */
27757
27758/* include removed: duk_internal.h */
27759
27760/*
27761 * Encoding/decoding helpers
27762 */
27763
27764/* XXX: Could add fast path (for each transform callback) with direct byte
27765 * lookups (no shifting) and no explicit check for x < 0x80 before table
27766 * lookup.
27767 */
27768
27769/* Macros for creating and checking bitmasks for character encoding.
27770 * Bit number is a bit counterintuitive, but minimizes code size.
27771 */
27772#define DUK__MKBITS(a,b,c,d,e,f,g,h) ((duk_uint8_t) ( \
27773 ((a) << 0) | ((b) << 1) | ((c) << 2) | ((d) << 3) | \
27774 ((e) << 4) | ((f) << 5) | ((g) << 6) | ((h) << 7) \
27775 ))
27776#define DUK__CHECK_BITMASK(table,cp) ((table)[(cp) >> 3] & (1 << ((cp) & 0x07)))
27777
27778/* E5.1 Section 15.1.3.3: uriReserved + uriUnescaped + '#' */
27779DUK_LOCAL const duk_uint8_t duk__encode_uriunescaped_table[16] = {
27780 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
27781 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
27782 DUK__MKBITS(0, 1, 0, 1, 1, 0, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x20-0x2f */
27783 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 0, 1, 0, 1), /* 0x30-0x3f */
27784 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */
27785 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */
27786 DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */
27787 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 1, 0), /* 0x70-0x7f */
27788};
27789
27790/* E5.1 Section 15.1.3.4: uriUnescaped */
27791DUK_LOCAL const duk_uint8_t duk__encode_uricomponent_unescaped_table[16] = {
27792 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
27793 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
27794 DUK__MKBITS(0, 1, 0, 0, 0, 0, 0, 1), DUK__MKBITS(1, 1, 1, 0, 0, 1, 1, 0), /* 0x20-0x2f */
27795 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */
27796 DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */
27797 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */
27798 DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */
27799 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 1, 0), /* 0x70-0x7f */
27800};
27801
27802/* E5.1 Section 15.1.3.1: uriReserved + '#' */
27803DUK_LOCAL const duk_uint8_t duk__decode_uri_reserved_table[16] = {
27804 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
27805 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
27806 DUK__MKBITS(0, 0, 0, 1, 1, 0, 1, 0), DUK__MKBITS(0, 0, 0, 1, 1, 0, 0, 1), /* 0x20-0x2f */
27807 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 1, 1, 0, 1, 0, 1), /* 0x30-0x3f */
27808 DUK__MKBITS(1, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x40-0x4f */
27809 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x50-0x5f */
27810 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x60-0x6f */
27811 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x70-0x7f */
27812};
27813
27814/* E5.1 Section 15.1.3.2: empty */
27815DUK_LOCAL const duk_uint8_t duk__decode_uri_component_reserved_table[16] = {
27816 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
27817 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
27818 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x20-0x2f */
27819 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */
27820 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x40-0x4f */
27821 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x50-0x5f */
27822 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x60-0x6f */
27823 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x70-0x7f */
27824};
27825
27826#ifdef DUK_USE_SECTION_B
27827/* E5.1 Section B.2.2, step 7. */
27828DUK_LOCAL const duk_uint8_t duk__escape_unescaped_table[16] = {
27829 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
27830 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
27831 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 1, 1, 0, 1, 1, 1), /* 0x20-0x2f */
27832 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */
27833 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */
27834 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */
27835 DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */
27836 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 0) /* 0x70-0x7f */
27837};
27838#endif /* DUK_USE_SECTION_B */
27839
27840#undef DUK__MKBITS
27841
27842typedef struct {
27843 duk_hthread *thr;
27844 duk_hstring *h_str;
27845 duk_bufwriter_ctx bw;
27846 const duk_uint8_t *p;
27847 const duk_uint8_t *p_start;
27848 const duk_uint8_t *p_end;
27849} duk__transform_context;
27850
11fdf7f2 27851typedef void (*duk__transform_callback)(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp);
7c673cae
FG
27852
27853/* XXX: refactor and share with other code */
27854DUK_LOCAL duk_small_int_t duk__decode_hex_escape(const duk_uint8_t *p, duk_small_int_t n) {
27855 duk_small_int_t ch;
27856 duk_small_int_t t = 0;
27857
27858 while (n > 0) {
27859 t = t * 16;
27860 ch = (duk_small_int_t) duk_hex_dectab[*p++];
27861 if (DUK_LIKELY(ch >= 0)) {
27862 t += ch;
27863 } else {
27864 return -1;
27865 }
27866 n--;
27867 }
27868 return t;
27869}
27870
11fdf7f2 27871DUK_LOCAL int duk__transform_helper(duk_context *ctx, duk__transform_callback callback, const void *udata) {
7c673cae
FG
27872 duk_hthread *thr = (duk_hthread *) ctx;
27873 duk__transform_context tfm_ctx_alloc;
27874 duk__transform_context *tfm_ctx = &tfm_ctx_alloc;
27875 duk_codepoint_t cp;
27876
27877 tfm_ctx->thr = thr;
27878
27879 tfm_ctx->h_str = duk_to_hstring(ctx, 0);
27880 DUK_ASSERT(tfm_ctx->h_str != NULL);
27881
27882 DUK_BW_INIT_PUSHBUF(thr, &tfm_ctx->bw, DUK_HSTRING_GET_BYTELEN(tfm_ctx->h_str)); /* initial size guess */
27883
27884 tfm_ctx->p_start = DUK_HSTRING_GET_DATA(tfm_ctx->h_str);
27885 tfm_ctx->p_end = tfm_ctx->p_start + DUK_HSTRING_GET_BYTELEN(tfm_ctx->h_str);
27886 tfm_ctx->p = tfm_ctx->p_start;
27887
27888 while (tfm_ctx->p < tfm_ctx->p_end) {
27889 cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &tfm_ctx->p, tfm_ctx->p_start, tfm_ctx->p_end);
27890 callback(tfm_ctx, udata, cp);
27891 }
27892
27893 DUK_BW_COMPACT(thr, &tfm_ctx->bw);
27894
27895 duk_to_string(ctx, -1);
27896 return 1;
27897}
27898
11fdf7f2 27899DUK_LOCAL void duk__transform_callback_encode_uri(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
7c673cae
FG
27900 duk_uint8_t xutf8_buf[DUK_UNICODE_MAX_XUTF8_LENGTH];
27901 duk_small_int_t len;
27902 duk_codepoint_t cp1, cp2;
27903 duk_small_int_t i, t;
11fdf7f2 27904 const duk_uint8_t *unescaped_table = (const duk_uint8_t *) udata;
7c673cae
FG
27905
27906 /* UTF-8 encoded bytes escaped as %xx%xx%xx... -> 3 * nbytes.
27907 * Codepoint range is restricted so this is a slightly too large
27908 * but doesn't matter.
27909 */
27910 DUK_BW_ENSURE(tfm_ctx->thr, &tfm_ctx->bw, 3 * DUK_UNICODE_MAX_XUTF8_LENGTH);
27911
27912 if (cp < 0) {
27913 goto uri_error;
27914 } else if ((cp < 0x80L) && DUK__CHECK_BITMASK(unescaped_table, cp)) {
27915 DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t) cp);
27916 return;
27917 } else if (cp >= 0xdc00L && cp <= 0xdfffL) {
27918 goto uri_error;
27919 } else if (cp >= 0xd800L && cp <= 0xdbffL) {
27920 /* Needs lookahead */
27921 if (duk_unicode_decode_xutf8(tfm_ctx->thr, &tfm_ctx->p, tfm_ctx->p_start, tfm_ctx->p_end, (duk_ucodepoint_t *) &cp2) == 0) {
27922 goto uri_error;
27923 }
27924 if (!(cp2 >= 0xdc00L && cp2 <= 0xdfffL)) {
27925 goto uri_error;
27926 }
27927 cp1 = cp;
27928 cp = ((cp1 - 0xd800L) << 10) + (cp2 - 0xdc00L) + 0x10000L;
27929 } else if (cp > 0x10ffffL) {
27930 /* Although we can allow non-BMP characters (they'll decode
27931 * back into surrogate pairs), we don't allow extended UTF-8
27932 * characters; they would encode to URIs which won't decode
27933 * back because of strict UTF-8 checks in URI decoding.
27934 * (However, we could just as well allow them here.)
27935 */
27936 goto uri_error;
27937 } else {
27938 /* Non-BMP characters within valid UTF-8 range: encode as is.
27939 * They'll decode back into surrogate pairs if the escaped
27940 * output is decoded.
27941 */
27942 ;
27943 }
27944
27945 len = duk_unicode_encode_xutf8((duk_ucodepoint_t) cp, xutf8_buf);
27946 for (i = 0; i < len; i++) {
27947 t = (int) xutf8_buf[i];
27948 DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr,
27949 &tfm_ctx->bw,
27950 DUK_ASC_PERCENT,
27951 (duk_uint8_t) duk_uc_nybbles[t >> 4],
27952 (duk_uint8_t) duk_uc_nybbles[t & 0x0f]);
27953 }
27954
27955 return;
27956
27957 uri_error:
27958 DUK_ERROR(tfm_ctx->thr, DUK_ERR_URI_ERROR, "invalid input");
27959}
27960
11fdf7f2
TL
27961DUK_LOCAL void duk__transform_callback_decode_uri(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
27962 const duk_uint8_t *reserved_table = (const duk_uint8_t *) udata;
7c673cae
FG
27963 duk_small_uint_t utf8_blen;
27964 duk_codepoint_t min_cp;
27965 duk_small_int_t t; /* must be signed */
27966 duk_small_uint_t i;
27967
27968 /* Maximum write size: XUTF8 path writes max DUK_UNICODE_MAX_XUTF8_LENGTH,
27969 * percent escape path writes max two times CESU-8 encoded BMP length.
27970 */
27971 DUK_BW_ENSURE(tfm_ctx->thr,
27972 &tfm_ctx->bw,
27973 (DUK_UNICODE_MAX_XUTF8_LENGTH >= 2 * DUK_UNICODE_MAX_CESU8_BMP_LENGTH ?
27974 DUK_UNICODE_MAX_XUTF8_LENGTH : DUK_UNICODE_MAX_CESU8_BMP_LENGTH));
27975
27976 if (cp == (duk_codepoint_t) '%') {
27977 const duk_uint8_t *p = tfm_ctx->p;
27978 duk_size_t left = (duk_size_t) (tfm_ctx->p_end - p); /* bytes left */
27979
27980 DUK_DDD(DUK_DDDPRINT("percent encoding, left=%ld", (long) left));
27981
27982 if (left < 2) {
27983 goto uri_error;
27984 }
27985
27986 t = duk__decode_hex_escape(p, 2);
27987 DUK_DDD(DUK_DDDPRINT("first byte: %ld", (long) t));
27988 if (t < 0) {
27989 goto uri_error;
27990 }
27991
27992 if (t < 0x80) {
27993 if (DUK__CHECK_BITMASK(reserved_table, t)) {
27994 /* decode '%xx' to '%xx' if decoded char in reserved set */
27995 DUK_ASSERT(tfm_ctx->p - 1 >= tfm_ctx->p_start);
27996 DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr,
27997 &tfm_ctx->bw,
27998 DUK_ASC_PERCENT,
27999 p[0],
28000 p[1]);
28001 } else {
28002 DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t) t);
28003 }
28004 tfm_ctx->p += 2;
28005 return;
28006 }
28007
28008 /* Decode UTF-8 codepoint from a sequence of hex escapes. The
28009 * first byte of the sequence has been decoded to 't'.
28010 *
28011 * Note that UTF-8 validation must be strict according to the
28012 * specification: E5.1 Section 15.1.3, decode algorithm step
28013 * 4.d.vii.8. URIError from non-shortest encodings is also
28014 * specifically noted in the spec.
28015 */
28016
28017 DUK_ASSERT(t >= 0x80);
28018 if (t < 0xc0) {
28019 /* continuation byte */
28020 goto uri_error;
28021 } else if (t < 0xe0) {
28022 /* 110x xxxx; 2 bytes */
28023 utf8_blen = 2;
28024 min_cp = 0x80L;
28025 cp = t & 0x1f;
28026 } else if (t < 0xf0) {
28027 /* 1110 xxxx; 3 bytes */
28028 utf8_blen = 3;
28029 min_cp = 0x800L;
28030 cp = t & 0x0f;
28031 } else if (t < 0xf8) {
28032 /* 1111 0xxx; 4 bytes */
28033 utf8_blen = 4;
28034 min_cp = 0x10000L;
28035 cp = t & 0x07;
28036 } else {
28037 /* extended utf-8 not allowed for URIs */
28038 goto uri_error;
28039 }
28040
28041 if (left < utf8_blen * 3 - 1) {
28042 /* '%xx%xx...%xx', p points to char after first '%' */
28043 goto uri_error;
28044 }
28045
28046 p += 3;
28047 for (i = 1; i < utf8_blen; i++) {
28048 /* p points to digit part ('%xy', p points to 'x') */
28049 t = duk__decode_hex_escape(p, 2);
28050 DUK_DDD(DUK_DDDPRINT("i=%ld utf8_blen=%ld cp=%ld t=0x%02lx",
28051 (long) i, (long) utf8_blen, (long) cp, (unsigned long) t));
28052 if (t < 0) {
28053 goto uri_error;
28054 }
28055 if ((t & 0xc0) != 0x80) {
28056 goto uri_error;
28057 }
28058 cp = (cp << 6) + (t & 0x3f);
28059 p += 3;
28060 }
28061 p--; /* p overshoots */
28062 tfm_ctx->p = p;
28063
28064 DUK_DDD(DUK_DDDPRINT("final cp=%ld, min_cp=%ld", (long) cp, (long) min_cp));
28065
28066 if (cp < min_cp || cp > 0x10ffffL || (cp >= 0xd800L && cp <= 0xdfffL)) {
28067 goto uri_error;
28068 }
28069
28070 /* The E5.1 algorithm checks whether or not a decoded codepoint
28071 * is below 0x80 and perhaps may be in the "reserved" set.
28072 * This seems pointless because the single byte UTF-8 case is
28073 * handled separately, and non-shortest encodings are rejected.
28074 * So, 'cp' cannot be below 0x80 here, and thus cannot be in
28075 * the reserved set.
28076 */
28077
28078 /* utf-8 validation ensures these */
28079 DUK_ASSERT(cp >= 0x80L && cp <= 0x10ffffL);
28080
28081 if (cp >= 0x10000L) {
28082 cp -= 0x10000L;
28083 DUK_ASSERT(cp < 0x100000L);
28084
28085 DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, ((cp >> 10) + 0xd800L));
28086 DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, ((cp & 0x03ffUL) + 0xdc00L));
28087 } else {
28088 DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp);
28089 }
28090 } else {
28091 DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp);
28092 }
28093 return;
28094
28095 uri_error:
28096 DUK_ERROR(tfm_ctx->thr, DUK_ERR_URI_ERROR, "invalid input");
28097}
28098
28099#ifdef DUK_USE_SECTION_B
11fdf7f2 28100DUK_LOCAL void duk__transform_callback_escape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
7c673cae
FG
28101 DUK_UNREF(udata);
28102
28103 DUK_BW_ENSURE(tfm_ctx->thr, &tfm_ctx->bw, 6);
28104
28105 if (cp < 0) {
28106 goto esc_error;
28107 } else if ((cp < 0x80L) && DUK__CHECK_BITMASK(duk__escape_unescaped_table, cp)) {
28108 DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t) cp);
28109 } else if (cp < 0x100L) {
28110 DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr,
28111 &tfm_ctx->bw,
28112 (duk_uint8_t) DUK_ASC_PERCENT,
28113 (duk_uint8_t) duk_uc_nybbles[cp >> 4],
28114 (duk_uint8_t) duk_uc_nybbles[cp & 0x0f]);
28115 } else if (cp < 0x10000L) {
28116 DUK_BW_WRITE_RAW_U8_6(tfm_ctx->thr,
28117 &tfm_ctx->bw,
28118 (duk_uint8_t) DUK_ASC_PERCENT,
28119 (duk_uint8_t) DUK_ASC_LC_U,
28120 (duk_uint8_t) duk_uc_nybbles[cp >> 12],
28121 (duk_uint8_t) duk_uc_nybbles[(cp >> 8) & 0x0f],
28122 (duk_uint8_t) duk_uc_nybbles[(cp >> 4) & 0x0f],
28123 (duk_uint8_t) duk_uc_nybbles[cp & 0x0f]);
28124 } else {
28125 /* Characters outside BMP cannot be escape()'d. We could
28126 * encode them as surrogate pairs (for codepoints inside
28127 * valid UTF-8 range, but not extended UTF-8). Because
28128 * escape() and unescape() are legacy functions, we don't.
28129 */
28130 goto esc_error;
28131 }
28132
28133 return;
28134
28135 esc_error:
11fdf7f2 28136 DUK_ERROR_TYPE(tfm_ctx->thr, "invalid input");
7c673cae
FG
28137}
28138
11fdf7f2 28139DUK_LOCAL void duk__transform_callback_unescape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
7c673cae
FG
28140 duk_small_int_t t;
28141
28142 DUK_UNREF(udata);
28143
28144 if (cp == (duk_codepoint_t) '%') {
28145 const duk_uint8_t *p = tfm_ctx->p;
28146 duk_size_t left = (duk_size_t) (tfm_ctx->p_end - p); /* bytes left */
28147
28148 if (left >= 5 && p[0] == 'u' &&
28149 ((t = duk__decode_hex_escape(p + 1, 4)) >= 0)) {
28150 cp = (duk_codepoint_t) t;
28151 tfm_ctx->p += 5;
28152 } else if (left >= 2 &&
28153 ((t = duk__decode_hex_escape(p, 2)) >= 0)) {
28154 cp = (duk_codepoint_t) t;
28155 tfm_ctx->p += 2;
28156 }
28157 }
28158
28159 DUK_BW_WRITE_ENSURE_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp);
28160}
28161#endif /* DUK_USE_SECTION_B */
28162
28163/*
28164 * Eval
28165 *
28166 * Eval needs to handle both a "direct eval" and an "indirect eval".
28167 * Direct eval handling needs access to the caller's activation so that its
28168 * lexical environment can be accessed. A direct eval is only possible from
28169 * Ecmascript code; an indirect eval call is possible also from C code.
28170 * When an indirect eval call is made from C code, there may not be a
28171 * calling activation at all which needs careful handling.
28172 */
28173
28174DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
28175 duk_hthread *thr = (duk_hthread *) ctx;
28176 duk_hstring *h;
28177 duk_activation *act_caller;
28178 duk_activation *act_eval;
28179 duk_activation *act;
28180 duk_hcompiledfunction *func;
28181 duk_hobject *outer_lex_env;
28182 duk_hobject *outer_var_env;
28183 duk_bool_t this_to_global = 1;
28184 duk_small_uint_t comp_flags;
11fdf7f2 28185 duk_int_t level = -2;
7c673cae 28186
11fdf7f2 28187 DUK_ASSERT(duk_get_top(ctx) == 1 || duk_get_top(ctx) == 2); /* 2 when called by debugger */
7c673cae
FG
28188 DUK_ASSERT(thr->callstack_top >= 1); /* at least this function exists */
28189 DUK_ASSERT(((thr->callstack + thr->callstack_top - 1)->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0 || /* indirect eval */
28190 (thr->callstack_top >= 2)); /* if direct eval, calling activation must exist */
28191
28192 /*
28193 * callstack_top - 1 --> this function
28194 * callstack_top - 2 --> caller (may not exist)
28195 *
28196 * If called directly from C, callstack_top might be 1. If calling
28197 * activation doesn't exist, call must be indirect.
28198 */
28199
28200 h = duk_get_hstring(ctx, 0);
28201 if (!h) {
28202 return 1; /* return arg as-is */
28203 }
28204
11fdf7f2
TL
28205#if defined(DUK_USE_DEBUGGER_SUPPORT)
28206 /* NOTE: level is used only by the debugger and should never be present
28207 * for an Ecmascript eval().
28208 */
28209 DUK_ASSERT(level == -2); /* by default, use caller's environment */
28210 if (duk_get_top(ctx) >= 2 && duk_is_number(ctx, 1)) {
28211 level = duk_get_int(ctx, 1);
28212 }
28213 DUK_ASSERT(level <= -2); /* This is guaranteed by debugger code. */
28214#endif
28215
7c673cae
FG
28216 /* [ source ] */
28217
28218 comp_flags = DUK_JS_COMPILE_FLAG_EVAL;
28219 act_eval = thr->callstack + thr->callstack_top - 1; /* this function */
11fdf7f2 28220 if (thr->callstack_top >= (duk_size_t) -level) {
7c673cae
FG
28221 /* Have a calling activation, check for direct eval (otherwise
28222 * assume indirect eval.
28223 */
11fdf7f2 28224 act_caller = thr->callstack + thr->callstack_top + level; /* caller */
7c673cae
FG
28225 if ((act_caller->flags & DUK_ACT_FLAG_STRICT) &&
28226 (act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL)) {
28227 /* Only direct eval inherits strictness from calling code
28228 * (E5.1 Section 10.1.1).
28229 */
28230 comp_flags |= DUK_JS_COMPILE_FLAG_STRICT;
28231 }
28232 } else {
28233 DUK_ASSERT((act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0);
28234 }
28235 act_caller = NULL; /* avoid dereference after potential callstack realloc */
28236 act_eval = NULL;
28237
28238 duk_push_hstring_stridx(ctx, DUK_STRIDX_INPUT); /* XXX: copy from caller? */
28239 duk_js_compile(thr,
28240 (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h),
28241 (duk_size_t) DUK_HSTRING_GET_BYTELEN(h),
28242 comp_flags);
28243 func = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);
28244 DUK_ASSERT(func != NULL);
28245 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) func));
28246
28247 /* [ source template ] */
28248
28249 /* E5 Section 10.4.2 */
28250 DUK_ASSERT(thr->callstack_top >= 1);
28251 act = thr->callstack + thr->callstack_top - 1; /* this function */
28252 if (act->flags & DUK_ACT_FLAG_DIRECT_EVAL) {
28253 DUK_ASSERT(thr->callstack_top >= 2);
11fdf7f2 28254 act = thr->callstack + thr->callstack_top + level; /* caller */
7c673cae
FG
28255 if (act->lex_env == NULL) {
28256 DUK_ASSERT(act->var_env == NULL);
28257 DUK_DDD(DUK_DDDPRINT("delayed environment initialization"));
28258
28259 /* this may have side effects, so re-lookup act */
28260 duk_js_init_activation_environment_records_delayed(thr, act);
11fdf7f2 28261 act = thr->callstack + thr->callstack_top + level;
7c673cae
FG
28262 }
28263 DUK_ASSERT(act->lex_env != NULL);
28264 DUK_ASSERT(act->var_env != NULL);
28265
28266 this_to_global = 0;
28267
28268 if (DUK_HOBJECT_HAS_STRICT((duk_hobject *) func)) {
28269 duk_hobject *new_env;
28270 duk_hobject *act_lex_env;
28271
28272 DUK_DDD(DUK_DDDPRINT("direct eval call to a strict function -> "
28273 "var_env and lex_env to a fresh env, "
28274 "this_binding to caller's this_binding"));
28275
7c673cae
FG
28276 act_lex_env = act->lex_env;
28277 act = NULL; /* invalidated */
28278
28279 (void) duk_push_object_helper_proto(ctx,
28280 DUK_HOBJECT_FLAG_EXTENSIBLE |
28281 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
28282 act_lex_env);
28283 new_env = duk_require_hobject(ctx, -1);
28284 DUK_ASSERT(new_env != NULL);
28285 DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO",
28286 (duk_heaphdr *) new_env));
28287
28288 outer_lex_env = new_env;
28289 outer_var_env = new_env;
28290
11fdf7f2 28291 duk_insert(ctx, 0); /* stash to bottom of value stack to keep new_env reachable for duration of eval */
7c673cae
FG
28292
28293 /* compiler's responsibility */
28294 DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV((duk_hobject *) func));
28295 } else {
28296 DUK_DDD(DUK_DDDPRINT("direct eval call to a non-strict function -> "
28297 "var_env and lex_env to caller's envs, "
28298 "this_binding to caller's this_binding"));
28299
28300 outer_lex_env = act->lex_env;
28301 outer_var_env = act->var_env;
28302
28303 /* compiler's responsibility */
28304 DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV((duk_hobject *) func));
28305 }
28306 } else {
28307 DUK_DDD(DUK_DDDPRINT("indirect eval call -> var_env and lex_env to "
28308 "global object, this_binding to global object"));
28309
28310 this_to_global = 1;
28311 outer_lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
28312 outer_var_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
28313 }
28314 act = NULL;
28315
11fdf7f2
TL
28316 /* Eval code doesn't need an automatic .prototype object. */
28317 duk_js_push_closure(thr, func, outer_var_env, outer_lex_env, 0 /*add_auto_proto*/);
7c673cae
FG
28318
28319 /* [ source template closure ] */
28320
28321 if (this_to_global) {
28322 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
28323 duk_push_hobject_bidx(ctx, DUK_BIDX_GLOBAL);
28324 } else {
28325 duk_tval *tv;
28326 DUK_ASSERT(thr->callstack_top >= 2);
11fdf7f2 28327 act = thr->callstack + thr->callstack_top + level; /* caller */
7c673cae
FG
28328 tv = thr->valstack + act->idx_bottom - 1; /* this is just beneath bottom */
28329 DUK_ASSERT(tv >= thr->valstack);
28330 duk_push_tval(ctx, tv);
28331 }
28332
28333 DUK_DDD(DUK_DDDPRINT("eval -> lex_env=%!iO, var_env=%!iO, this_binding=%!T",
28334 (duk_heaphdr *) outer_lex_env,
28335 (duk_heaphdr *) outer_var_env,
11fdf7f2 28336 duk_get_tval(ctx, -1)));
7c673cae
FG
28337
28338 /* [ source template closure this ] */
28339
28340 duk_call_method(ctx, 0);
28341
28342 /* [ source template result ] */
28343
28344 return 1;
28345}
28346
28347/*
28348 * Parsing of ints and floats
28349 */
28350
28351DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx) {
7c673cae
FG
28352 duk_int32_t radix;
28353 duk_small_uint_t s2n_flags;
28354
28355 DUK_ASSERT_TOP(ctx, 2);
28356 duk_to_string(ctx, 0);
28357
7c673cae 28358 radix = duk_to_int32(ctx, 1);
11fdf7f2
TL
28359
28360 s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
28361 DUK_S2N_FLAG_ALLOW_GARBAGE |
28362 DUK_S2N_FLAG_ALLOW_PLUS |
28363 DUK_S2N_FLAG_ALLOW_MINUS |
28364 DUK_S2N_FLAG_ALLOW_LEADING_ZERO |
28365 DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT;
28366
28367 /* Specification stripPrefix maps to DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT.
28368 *
28369 * Don't autodetect octals (from leading zeroes), require user code to
28370 * provide an explicit radix 8 for parsing octal. See write-up from Mozilla:
28371 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt#ECMAScript_5_Removes_Octal_Interpretation
28372 */
28373
7c673cae
FG
28374 if (radix != 0) {
28375 if (radix < 2 || radix > 36) {
28376 goto ret_nan;
28377 }
7c673cae 28378 if (radix != 16) {
11fdf7f2 28379 s2n_flags &= ~DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT;
7c673cae
FG
28380 }
28381 } else {
28382 radix = 10;
28383 }
28384
7c673cae
FG
28385 duk_dup(ctx, 0);
28386 duk_numconv_parse(ctx, radix, s2n_flags);
28387 return 1;
28388
28389 ret_nan:
28390 duk_push_nan(ctx);
28391 return 1;
28392}
28393
28394DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx) {
28395 duk_small_uint_t s2n_flags;
28396 duk_int32_t radix;
28397
28398 DUK_ASSERT_TOP(ctx, 1);
28399 duk_to_string(ctx, 0);
28400
28401 radix = 10;
28402
28403 /* XXX: check flags */
28404 s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
28405 DUK_S2N_FLAG_ALLOW_EXP |
28406 DUK_S2N_FLAG_ALLOW_GARBAGE |
28407 DUK_S2N_FLAG_ALLOW_PLUS |
28408 DUK_S2N_FLAG_ALLOW_MINUS |
28409 DUK_S2N_FLAG_ALLOW_INF |
28410 DUK_S2N_FLAG_ALLOW_FRAC |
28411 DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
28412 DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
28413 DUK_S2N_FLAG_ALLOW_LEADING_ZERO;
28414
28415 duk_numconv_parse(ctx, radix, s2n_flags);
28416 return 1;
28417}
28418
28419/*
28420 * Number checkers
28421 */
28422
28423DUK_INTERNAL duk_ret_t duk_bi_global_object_is_nan(duk_context *ctx) {
28424 duk_double_t d = duk_to_number(ctx, 0);
28425 duk_push_boolean(ctx, DUK_ISNAN(d));
28426 return 1;
28427}
28428
28429DUK_INTERNAL duk_ret_t duk_bi_global_object_is_finite(duk_context *ctx) {
28430 duk_double_t d = duk_to_number(ctx, 0);
28431 duk_push_boolean(ctx, DUK_ISFINITE(d));
28432 return 1;
28433}
28434
28435/*
28436 * URI handling
28437 */
28438
28439DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri(duk_context *ctx) {
11fdf7f2 28440 return duk__transform_helper(ctx, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_reserved_table);
7c673cae
FG
28441}
28442
28443DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri_component(duk_context *ctx) {
11fdf7f2 28444 return duk__transform_helper(ctx, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_component_reserved_table);
7c673cae
FG
28445}
28446
28447DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri(duk_context *ctx) {
11fdf7f2 28448 return duk__transform_helper(ctx, duk__transform_callback_encode_uri, (const void *) duk__encode_uriunescaped_table);
7c673cae
FG
28449}
28450
28451DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri_component(duk_context *ctx) {
11fdf7f2 28452 return duk__transform_helper(ctx, duk__transform_callback_encode_uri, (const void *) duk__encode_uricomponent_unescaped_table);
7c673cae
FG
28453}
28454
28455#ifdef DUK_USE_SECTION_B
28456DUK_INTERNAL duk_ret_t duk_bi_global_object_escape(duk_context *ctx) {
11fdf7f2 28457 return duk__transform_helper(ctx, duk__transform_callback_escape, (const void *) NULL);
7c673cae
FG
28458}
28459
28460DUK_INTERNAL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx) {
11fdf7f2 28461 return duk__transform_helper(ctx, duk__transform_callback_unescape, (const void *) NULL);
7c673cae
FG
28462}
28463#else /* DUK_USE_SECTION_B */
28464DUK_INTERNAL duk_ret_t duk_bi_global_object_escape(duk_context *ctx) {
28465 DUK_UNREF(ctx);
28466 return DUK_RET_UNSUPPORTED_ERROR;
28467}
28468
28469DUK_INTERNAL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx) {
28470 DUK_UNREF(ctx);
28471 return DUK_RET_UNSUPPORTED_ERROR;
28472}
28473#endif /* DUK_USE_SECTION_B */
28474
28475#if defined(DUK_USE_BROWSER_LIKE) && (defined(DUK_USE_FILE_IO) || defined(DUK_USE_DEBUGGER_SUPPORT))
28476DUK_INTERNAL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx) {
28477 duk_hthread *thr = (duk_hthread *) ctx;
28478 duk_int_t magic;
28479 duk_idx_t nargs;
28480 const duk_uint8_t *buf;
28481 duk_size_t sz_buf;
28482 const char nl = (const char) DUK_ASC_LF;
28483#ifndef DUK_USE_PREFER_SIZE
28484 duk_uint8_t buf_stack[256];
28485#endif
28486#ifdef DUK_USE_FILE_IO
28487 duk_file *f_out;
28488#endif
28489
11fdf7f2
TL
28490 DUK_UNREF(thr);
28491
7c673cae
FG
28492 magic = duk_get_current_magic(ctx);
28493 DUK_UNREF(magic);
28494
28495 nargs = duk_get_top(ctx);
28496
28497 /* If argument count is 1 and first argument is a buffer, write the buffer
28498 * as raw data into the file without a newline; this allows exact control
28499 * over stdout/stderr without an additional entrypoint (useful for now).
28500 *
28501 * Otherwise current print/alert semantics are to ToString() coerce
28502 * arguments, join them with a single space, and append a newline.
28503 */
28504
28505 if (nargs == 1 && duk_is_buffer(ctx, 0)) {
28506 buf = (const duk_uint8_t *) duk_get_buffer(ctx, 0, &sz_buf);
28507 DUK_ASSERT(buf != NULL);
28508 } else if (nargs > 0) {
28509#ifdef DUK_USE_PREFER_SIZE
28510 /* Compact but lots of churn. */
28511 duk_push_hstring_stridx(thr, DUK_STRIDX_SPACE);
28512 duk_insert(ctx, 0);
28513 duk_join(ctx, nargs);
28514 duk_push_string(thr, "\n");
28515 duk_concat(ctx, 2);
28516 buf = (const duk_uint8_t *) duk_get_lstring(ctx, -1, &sz_buf);
28517 DUK_ASSERT(buf != NULL);
28518#else /* DUK_USE_PREFER_SIZE */
28519 /* Higher footprint, less churn. */
28520 duk_idx_t i;
28521 duk_size_t sz_str;
28522 const duk_uint8_t *p_str;
28523 duk_uint8_t *p;
28524
28525 sz_buf = (duk_size_t) nargs; /* spaces (nargs - 1) + newline */
28526 for (i = 0; i < nargs; i++) {
28527 (void) duk_to_lstring(ctx, i, &sz_str);
28528 sz_buf += sz_str;
28529 }
28530
28531 if (sz_buf <= sizeof(buf_stack)) {
11fdf7f2 28532 p = (duk_uint8_t *) buf_stack;
7c673cae 28533 } else {
11fdf7f2
TL
28534 p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, sz_buf);
28535 DUK_ASSERT(p != NULL);
7c673cae
FG
28536 }
28537
11fdf7f2 28538 buf = (const duk_uint8_t *) p;
7c673cae
FG
28539 for (i = 0; i < nargs; i++) {
28540 p_str = (const duk_uint8_t *) duk_get_lstring(ctx, i, &sz_str);
28541 DUK_ASSERT(p_str != NULL);
28542 DUK_MEMCPY((void *) p, (const void *) p_str, sz_str);
28543 p += sz_str;
28544 *p++ = (duk_uint8_t) (i == nargs - 1 ? DUK_ASC_LF : DUK_ASC_SPACE);
28545 }
11fdf7f2 28546 DUK_ASSERT((const duk_uint8_t *) p == buf + sz_buf);
7c673cae
FG
28547#endif /* DUK_USE_PREFER_SIZE */
28548 } else {
28549 buf = (const duk_uint8_t *) &nl;
28550 sz_buf = 1;
28551 }
28552
28553 /* 'buf' contains the string to write, 'sz_buf' contains the length
28554 * (which may be zero).
28555 */
28556 DUK_ASSERT(buf != NULL);
28557
28558 if (sz_buf == 0) {
28559 return 0;
28560 }
28561
28562#ifdef DUK_USE_FILE_IO
28563 f_out = (magic ? DUK_STDERR : DUK_STDOUT);
28564 DUK_FWRITE((const void *) buf, 1, (size_t) sz_buf, f_out);
28565 DUK_FFLUSH(f_out);
28566#endif
28567
28568#if defined(DUK_USE_DEBUGGER_SUPPORT) && defined(DUK_USE_DEBUGGER_FWD_PRINTALERT)
28569 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
28570 duk_debug_write_notify(thr, magic ? DUK_DBG_CMD_ALERT : DUK_DBG_CMD_PRINT);
28571 duk_debug_write_string(thr, (const char *) buf, sz_buf);
28572 duk_debug_write_eom(thr);
28573 }
28574#endif
28575 return 0;
28576}
28577#elif defined(DUK_USE_BROWSER_LIKE) /* print provider */
28578DUK_INTERNAL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx) {
28579 DUK_UNREF(ctx);
28580 return 0;
28581}
28582#else /* print provider */
28583DUK_INTERNAL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx) {
28584 DUK_UNREF(ctx);
28585 return DUK_RET_UNSUPPORTED_ERROR;
28586}
28587#endif /* print provider */
28588
28589/*
28590 * CommonJS require() and modules support
28591 */
28592
28593#if defined(DUK_USE_COMMONJS_MODULES)
28594DUK_LOCAL void duk__bi_global_resolve_module_id(duk_context *ctx, const char *req_id, const char *mod_id) {
28595 duk_hthread *thr = (duk_hthread *) ctx;
11fdf7f2 28596 duk_uint8_t buf[DUK_BI_COMMONJS_MODULE_ID_LIMIT];
7c673cae
FG
28597 duk_uint8_t *p;
28598 duk_uint8_t *q;
11fdf7f2
TL
28599 duk_uint8_t *q_last; /* last component */
28600 duk_int_t int_rc;
7c673cae
FG
28601
28602 DUK_ASSERT(req_id != NULL);
28603 /* mod_id may be NULL */
7c673cae
FG
28604
28605 /*
28606 * A few notes on the algorithm:
28607 *
28608 * - Terms are not allowed to begin with a period unless the term
28609 * is either '.' or '..'. This simplifies implementation (and
28610 * is within CommonJS modules specification).
28611 *
28612 * - There are few output bound checks here. This is on purpose:
11fdf7f2
TL
28613 * the resolution input is length checked and the output is never
28614 * longer than the input. The resolved output is written directly
28615 * over the input because it's never longer than the input at any
28616 * point in the algorithm.
7c673cae
FG
28617 *
28618 * - Non-ASCII characters are processed as individual bytes and
28619 * need no special treatment. However, U+0000 terminates the
28620 * algorithm; this is not an issue because U+0000 is not a
28621 * desirable term character anyway.
28622 */
28623
28624 /*
28625 * Set up the resolution input which is the requested ID directly
28626 * (if absolute or no current module path) or with current module
28627 * ID prepended (if relative and current module path exists).
28628 *
28629 * Suppose current module is 'foo/bar' and relative path is './quux'.
28630 * The 'bar' component must be replaced so the initial input here is
28631 * 'foo/bar/.././quux'.
28632 */
28633
7c673cae 28634 if (mod_id != NULL && req_id[0] == '.') {
11fdf7f2 28635 int_rc = DUK_SNPRINTF((char *) buf, sizeof(buf), "%s/../%s", mod_id, req_id);
7c673cae 28636 } else {
11fdf7f2
TL
28637 int_rc = DUK_SNPRINTF((char *) buf, sizeof(buf), "%s", req_id);
28638 }
28639 if (int_rc >= (duk_int_t) sizeof(buf) || int_rc < 0) {
28640 /* Potentially truncated, NUL not guaranteed in any case.
28641 * The (int_rc < 0) case should not occur in practice.
28642 */
28643 DUK_DD(DUK_DDPRINT("resolve error: temporary working module ID doesn't fit into resolve buffer"));
28644 goto resolve_error;
7c673cae 28645 }
11fdf7f2 28646 DUK_ASSERT(DUK_STRLEN((const char *) buf) < sizeof(buf)); /* at most sizeof(buf) - 1 */
7c673cae 28647
11fdf7f2 28648 DUK_DDD(DUK_DDDPRINT("input module id: '%s'", (const char *) buf));
7c673cae
FG
28649
28650 /*
28651 * Resolution loop. At the top of the loop we're expecting a valid
28652 * term: '.', '..', or a non-empty identifier not starting with a period.
28653 */
28654
11fdf7f2
TL
28655 p = buf;
28656 q = buf;
7c673cae
FG
28657 for (;;) {
28658 duk_uint_fast8_t c;
28659
11fdf7f2
TL
28660 /* Here 'p' always points to the start of a term.
28661 *
28662 * We can also unconditionally reset q_last here: if this is
28663 * the last (non-empty) term q_last will have the right value
28664 * on loop exit.
28665 */
28666
28667 DUK_ASSERT(p >= q); /* output is never longer than input during resolution */
28668
28669 DUK_DDD(DUK_DDDPRINT("resolve loop top: p -> '%s', q=%p, buf=%p",
28670 (const char *) p, (void *) q, (void *) buf));
28671
28672 q_last = q;
7c673cae
FG
28673
28674 c = *p++;
28675 if (DUK_UNLIKELY(c == 0)) {
28676 DUK_DD(DUK_DDPRINT("resolve error: requested ID must end with a non-empty term"));
28677 goto resolve_error;
28678 } else if (DUK_UNLIKELY(c == '.')) {
28679 c = *p++;
28680 if (c == '/') {
28681 /* Term was '.' and is eaten entirely (including dup slashes). */
28682 goto eat_dup_slashes;
28683 }
28684 if (c == '.' && *p == '/') {
28685 /* Term was '..', backtrack resolved name by one component.
28686 * q[-1] = previous slash (or beyond start of buffer)
28687 * q[-2] = last char of previous component (or beyond start of buffer)
28688 */
28689 p++; /* eat (first) input slash */
11fdf7f2
TL
28690 DUK_ASSERT(q >= buf);
28691 if (q == buf) {
7c673cae
FG
28692 DUK_DD(DUK_DDPRINT("resolve error: term was '..' but nothing to backtrack"));
28693 goto resolve_error;
28694 }
28695 DUK_ASSERT(*(q - 1) == '/');
11fdf7f2 28696 q--; /* backtrack to last output slash (dups already eliminated) */
7c673cae
FG
28697 for (;;) {
28698 /* Backtrack to previous slash or start of buffer. */
11fdf7f2
TL
28699 DUK_ASSERT(q >= buf);
28700 if (q == buf) {
7c673cae
FG
28701 break;
28702 }
28703 if (*(q - 1) == '/') {
28704 break;
28705 }
28706 q--;
28707 }
28708 goto eat_dup_slashes;
28709 }
28710 DUK_DD(DUK_DDPRINT("resolve error: term begins with '.' but is not '.' or '..' (not allowed now)"));
28711 goto resolve_error;
28712 } else if (DUK_UNLIKELY(c == '/')) {
28713 /* e.g. require('/foo'), empty terms not allowed */
28714 DUK_DD(DUK_DDPRINT("resolve error: empty term (not allowed now)"));
28715 goto resolve_error;
28716 } else {
28717 for (;;) {
28718 /* Copy term name until end or '/'. */
28719 *q++ = c;
28720 c = *p++;
28721 if (DUK_UNLIKELY(c == 0)) {
11fdf7f2
TL
28722 /* This was the last term, and q_last was
28723 * updated to match this term at loop top.
28724 */
7c673cae
FG
28725 goto loop_done;
28726 } else if (DUK_UNLIKELY(c == '/')) {
28727 *q++ = '/';
28728 break;
28729 } else {
28730 /* write on next loop */
28731 }
28732 }
28733 }
28734
28735 eat_dup_slashes:
28736 for (;;) {
28737 /* eat dup slashes */
28738 c = *p;
28739 if (DUK_LIKELY(c != '/')) {
28740 break;
28741 }
28742 p++;
28743 }
28744 }
28745 loop_done:
11fdf7f2
TL
28746 /* Output #1: resolved absolute name */
28747 DUK_ASSERT(q >= buf);
28748 duk_push_lstring(ctx, (const char *) buf, (size_t) (q - buf));
28749
28750 /* Output #2: last component name */
28751 DUK_ASSERT(q >= q_last);
28752 DUK_ASSERT(q_last >= buf);
28753 duk_push_lstring(ctx, (const char *) q_last, (size_t) (q - q_last));
7c673cae 28754
11fdf7f2
TL
28755 DUK_DD(DUK_DDPRINT("after resolving module name: buf=%p, q_last=%p, q=%p",
28756 (void *) buf, (void *) q_last, (void *) q));
7c673cae
FG
28757 return;
28758
28759 resolve_error:
11fdf7f2 28760 DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "cannot resolve module id: %s", (const char *) req_id);
7c673cae
FG
28761}
28762#endif /* DUK_USE_COMMONJS_MODULES */
28763
28764#if defined(DUK_USE_COMMONJS_MODULES)
11fdf7f2
TL
28765/* Stack indices for better readability */
28766#define DUK__IDX_REQUESTED_ID 0 /* Module id requested */
28767#define DUK__IDX_REQUIRE 1 /* Current require() function */
28768#define DUK__IDX_REQUIRE_ID 2 /* The base ID of the current require() function, resolution base */
28769#define DUK__IDX_RESOLVED_ID 3 /* Resolved, normalized absolute module ID */
28770#define DUK__IDX_LASTCOMP 4 /* Last component name in resolved path */
28771#define DUK__IDX_DUKTAPE 5 /* Duktape object */
28772#define DUK__IDX_MODLOADED 6 /* Duktape.modLoaded[] module cache */
28773#define DUK__IDX_UNDEFINED 7 /* 'undefined', artifact of lookup */
28774#define DUK__IDX_FRESH_REQUIRE 8 /* New require() function for module, updated resolution base */
28775#define DUK__IDX_EXPORTS 9 /* Default exports table */
28776#define DUK__IDX_MODULE 10 /* Module object containing module.exports, etc */
28777
7c673cae
FG
28778DUK_INTERNAL duk_ret_t duk_bi_global_object_require(duk_context *ctx) {
28779 const char *str_req_id; /* requested identifier */
28780 const char *str_mod_id; /* require.id of current module */
28781 duk_int_t pcall_rc;
28782
28783 /* NOTE: we try to minimize code size by avoiding unnecessary pops,
28784 * so the stack looks a bit cluttered in this function. DUK_ASSERT_TOP()
28785 * assertions are used to ensure stack configuration is correct at each
28786 * step.
28787 */
28788
28789 /*
28790 * Resolve module identifier into canonical absolute form.
28791 */
28792
11fdf7f2 28793 str_req_id = duk_require_string(ctx, DUK__IDX_REQUESTED_ID);
7c673cae
FG
28794 duk_push_current_function(ctx);
28795 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_ID);
11fdf7f2 28796 str_mod_id = duk_get_string(ctx, DUK__IDX_REQUIRE_ID); /* ignore non-strings */
7c673cae 28797 DUK_DDD(DUK_DDDPRINT("resolve module id: requested=%!T, currentmodule=%!T",
11fdf7f2
TL
28798 duk_get_tval(ctx, DUK__IDX_REQUESTED_ID),
28799 duk_get_tval(ctx, DUK__IDX_REQUIRE_ID)));
7c673cae
FG
28800 duk__bi_global_resolve_module_id(ctx, str_req_id, str_mod_id);
28801 str_req_id = NULL;
28802 str_mod_id = NULL;
11fdf7f2
TL
28803 DUK_DDD(DUK_DDDPRINT("resolved module id: requested=%!T, currentmodule=%!T, result=%!T, lastcomp=%!T",
28804 duk_get_tval(ctx, DUK__IDX_REQUESTED_ID),
28805 duk_get_tval(ctx, DUK__IDX_REQUIRE_ID),
28806 duk_get_tval(ctx, DUK__IDX_RESOLVED_ID),
28807 duk_get_tval(ctx, DUK__IDX_LASTCOMP)));
7c673cae 28808
11fdf7f2
TL
28809 /* [ requested_id require require.id resolved_id last_comp ] */
28810 DUK_ASSERT_TOP(ctx, DUK__IDX_LASTCOMP + 1);
7c673cae
FG
28811
28812 /*
28813 * Cached module check.
28814 *
28815 * If module has been loaded or its loading has already begun without
28816 * finishing, return the same cached value ('exports'). The value is
28817 * registered when module load starts so that circular references can
28818 * be supported to some extent.
28819 */
28820
7c673cae 28821 duk_push_hobject_bidx(ctx, DUK_BIDX_DUKTAPE);
11fdf7f2
TL
28822 duk_get_prop_stridx(ctx, DUK__IDX_DUKTAPE, DUK_STRIDX_MOD_LOADED); /* Duktape.modLoaded */
28823 (void) duk_require_hobject(ctx, DUK__IDX_MODLOADED);
28824 DUK_ASSERT_TOP(ctx, DUK__IDX_MODLOADED + 1);
7c673cae 28825
11fdf7f2
TL
28826 duk_dup(ctx, DUK__IDX_RESOLVED_ID);
28827 if (duk_get_prop(ctx, DUK__IDX_MODLOADED)) {
28828 /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded Duktape.modLoaded[id] ] */
7c673cae 28829 DUK_DD(DUK_DDPRINT("module already loaded: %!T",
11fdf7f2 28830 duk_get_tval(ctx, DUK__IDX_RESOLVED_ID)));
7c673cae
FG
28831 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_EXPORTS); /* return module.exports */
28832 return 1;
28833 }
11fdf7f2 28834 DUK_ASSERT_TOP(ctx, DUK__IDX_UNDEFINED + 1);
7c673cae 28835
11fdf7f2 28836 /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined ] */
7c673cae
FG
28837
28838 /*
28839 * Module not loaded (and loading not started previously).
28840 *
28841 * Create a new require() function with 'id' set to resolved ID
28842 * of module being loaded. Also create 'exports' and 'module'
28843 * tables but don't register exports to the loaded table yet.
28844 * We don't want to do that unless the user module search callbacks
28845 * succeeds in finding the module.
28846 */
28847
11fdf7f2
TL
28848 DUK_D(DUK_DPRINT("loading module %!T, resolution base %!T, requested ID %!T -> resolved ID %!T, last component %!T",
28849 duk_get_tval(ctx, DUK__IDX_RESOLVED_ID),
28850 duk_get_tval(ctx, DUK__IDX_REQUIRE_ID),
28851 duk_get_tval(ctx, DUK__IDX_REQUESTED_ID),
28852 duk_get_tval(ctx, DUK__IDX_RESOLVED_ID),
28853 duk_get_tval(ctx, DUK__IDX_LASTCOMP)));
7c673cae
FG
28854
28855 /* Fresh require: require.id is left configurable (but not writable)
28856 * so that is not easy to accidentally tweak it, but it can still be
28857 * done with Object.defineProperty().
28858 *
28859 * XXX: require.id could also be just made non-configurable, as there
28860 * is no practical reason to touch it.
28861 */
28862 duk_push_c_function(ctx, duk_bi_global_object_require, 1 /*nargs*/);
11fdf7f2
TL
28863 duk_push_hstring_stridx(ctx, DUK_STRIDX_REQUIRE);
28864 duk_xdef_prop_stridx(ctx, DUK__IDX_FRESH_REQUIRE, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
28865 duk_dup(ctx, DUK__IDX_RESOLVED_ID);
28866 duk_xdef_prop_stridx(ctx, DUK__IDX_FRESH_REQUIRE, DUK_STRIDX_ID, DUK_PROPDESC_FLAGS_C); /* a fresh require() with require.id = resolved target module id */
7c673cae
FG
28867
28868 /* Module table:
28869 * - module.exports: initial exports table (may be replaced by user)
28870 * - module.id is non-writable and non-configurable, as the CommonJS
11fdf7f2
TL
28871 * spec suggests this if possible
28872 * - module.filename: not set, defaults to resolved ID if not explicitly
28873 * set by modSearch() (note capitalization, not .fileName, matches Node.js)
28874 * - module.name: not set, defaults to last component of resolved ID if
28875 * not explicitly set by modSearch()
7c673cae
FG
28876 */
28877 duk_push_object(ctx); /* exports */
28878 duk_push_object(ctx); /* module */
11fdf7f2
TL
28879 duk_dup(ctx, DUK__IDX_EXPORTS);
28880 duk_xdef_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_EXPORTS, DUK_PROPDESC_FLAGS_WC); /* module.exports = exports */
28881 duk_dup(ctx, DUK__IDX_RESOLVED_ID); /* resolved id: require(id) must return this same module */
28882 duk_xdef_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_ID, DUK_PROPDESC_FLAGS_NONE); /* module.id = resolved_id */
28883 duk_compact(ctx, DUK__IDX_MODULE); /* module table remains registered to modLoaded, minimize its size */
28884 DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 1);
28885
28886 DUK_DD(DUK_DDPRINT("module table created: %!T", duk_get_tval(ctx, DUK__IDX_MODULE)));
7c673cae 28887
11fdf7f2 28888 /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module ] */
7c673cae
FG
28889
28890 /* Register the module table early to modLoaded[] so that we can
28891 * support circular references even in modSearch(). If an error
28892 * is thrown, we'll delete the reference.
28893 */
11fdf7f2
TL
28894 duk_dup(ctx, DUK__IDX_RESOLVED_ID);
28895 duk_dup(ctx, DUK__IDX_MODULE);
28896 duk_put_prop(ctx, DUK__IDX_MODLOADED); /* Duktape.modLoaded[resolved_id] = module */
7c673cae
FG
28897
28898 /*
28899 * Call user provided module search function and build the wrapped
28900 * module source code (if necessary). The module search function
28901 * can be used to implement pure Ecmacsript, pure C, and mixed
28902 * Ecmascript/C modules.
28903 *
28904 * The module search function can operate on the exports table directly
28905 * (e.g. DLL code can register values to it). It can also return a
28906 * string which is interpreted as module source code (if a non-string
28907 * is returned the module is assumed to be a pure C one). If a module
28908 * cannot be found, an error must be thrown by the user callback.
28909 *
28910 * Because Duktape.modLoaded[] already contains the module being
28911 * loaded, circular references for C modules should also work
28912 * (although expected to be quite rare).
28913 */
28914
28915 duk_push_string(ctx, "(function(require,exports,module){");
28916
28917 /* Duktape.modSearch(resolved_id, fresh_require, exports, module). */
11fdf7f2
TL
28918 duk_get_prop_stridx(ctx, DUK__IDX_DUKTAPE, DUK_STRIDX_MOD_SEARCH); /* Duktape.modSearch */
28919 duk_dup(ctx, DUK__IDX_RESOLVED_ID);
28920 duk_dup(ctx, DUK__IDX_FRESH_REQUIRE);
28921 duk_dup(ctx, DUK__IDX_EXPORTS);
28922 duk_dup(ctx, DUK__IDX_MODULE); /* [ ... Duktape.modSearch resolved_id last_comp fresh_require exports module ] */
7c673cae 28923 pcall_rc = duk_pcall(ctx, 4 /*nargs*/); /* -> [ ... source ] */
11fdf7f2 28924 DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 3);
7c673cae
FG
28925
28926 if (pcall_rc != DUK_EXEC_SUCCESS) {
28927 /* Delete entry in Duktape.modLoaded[] and rethrow. */
28928 goto delete_rethrow;
28929 }
28930
28931 /* If user callback did not return source code, module loading
28932 * is finished (user callback initialized exports table directly).
28933 */
11fdf7f2 28934 if (!duk_is_string(ctx, -1)) {
7c673cae
FG
28935 /* User callback did not return source code, so module loading
28936 * is finished: just update modLoaded with final module.exports
28937 * and we're done.
28938 */
28939 goto return_exports;
28940 }
28941
11fdf7f2
TL
28942 /* Finish the wrapped module source. Force module.filename as the
28943 * function .fileName so it gets set for functions defined within a
28944 * module. This also ensures loggers created within the module get
28945 * the module ID (or overridden filename) as their default logger name.
28946 * (Note capitalization: .filename matches Node.js while .fileName is
28947 * used elsewhere in Duktape.)
7c673cae 28948 */
11fdf7f2 28949 duk_push_string(ctx, "\n})"); /* Newline allows module last line to contain a // comment. */
7c673cae 28950 duk_concat(ctx, 3);
11fdf7f2
TL
28951 if (!duk_get_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_FILENAME)) {
28952 /* module.filename for .fileName, default to resolved ID if
28953 * not present.
28954 */
28955 duk_pop(ctx);
28956 duk_dup(ctx, DUK__IDX_RESOLVED_ID);
28957 }
7c673cae
FG
28958 duk_eval_raw(ctx, NULL, 0, DUK_COMPILE_EVAL);
28959
11fdf7f2
TL
28960 /* Module has now evaluated to a wrapped module function. Force its
28961 * .name to match module.name (defaults to last component of resolved
28962 * ID) so that it is shown in stack traces too. Note that we must not
28963 * introduce an actual name binding into the function scope (which is
28964 * usually the case with a named function) because it would affect the
28965 * scope seen by the module and shadow accesses to globals of the same name.
28966 * This is now done by compiling the function as anonymous and then forcing
28967 * its .name without setting a "has name binding" flag.
7c673cae
FG
28968 */
28969
11fdf7f2
TL
28970 duk_push_hstring_stridx(ctx, DUK_STRIDX_NAME);
28971 if (!duk_get_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_NAME)) {
28972 /* module.name for .name, default to last component if
28973 * not present.
28974 */
28975 duk_pop(ctx);
28976 duk_dup(ctx, DUK__IDX_LASTCOMP);
28977 }
28978 duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_FORCE);
28979
7c673cae
FG
28980 /*
28981 * Call the wrapped module function.
28982 *
28983 * Use a protected call so that we can update Duktape.modLoaded[resolved_id]
28984 * even if the module throws an error.
28985 */
28986
11fdf7f2
TL
28987 /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module mod_func ] */
28988 DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 2);
7c673cae 28989
11fdf7f2
TL
28990 duk_dup(ctx, DUK__IDX_EXPORTS); /* exports (this binding) */
28991 duk_dup(ctx, DUK__IDX_FRESH_REQUIRE); /* fresh require (argument) */
28992 duk_get_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_EXPORTS); /* relookup exports from module.exports in case it was changed by modSearch */
28993 duk_dup(ctx, DUK__IDX_MODULE); /* module (argument) */
28994 DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 6);
7c673cae 28995
11fdf7f2 28996 /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module mod_func exports fresh_require exports module ] */
7c673cae
FG
28997
28998 pcall_rc = duk_pcall_method(ctx, 3 /*nargs*/);
28999 if (pcall_rc != DUK_EXEC_SUCCESS) {
29000 /* Module loading failed. Node.js will forget the module
29001 * registration so that another require() will try to load
29002 * the module again. Mimic that behavior.
29003 */
29004 goto delete_rethrow;
29005 }
29006
11fdf7f2
TL
29007 /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module result(ignored) ] */
29008 DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 2);
7c673cae
FG
29009
29010 /* fall through */
29011
29012 return_exports:
11fdf7f2
TL
29013 duk_get_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_EXPORTS);
29014 duk_compact(ctx, -1); /* compact the exports table */
7c673cae
FG
29015 return 1; /* return module.exports */
29016
29017 delete_rethrow:
11fdf7f2
TL
29018 duk_dup(ctx, DUK__IDX_RESOLVED_ID);
29019 duk_del_prop(ctx, DUK__IDX_MODLOADED); /* delete Duktape.modLoaded[resolved_id] */
7c673cae
FG
29020 duk_throw(ctx); /* rethrow original error */
29021 return 0; /* not reachable */
29022}
11fdf7f2
TL
29023
29024#undef DUK__IDX_REQUESTED_ID
29025#undef DUK__IDX_REQUIRE
29026#undef DUK__IDX_REQUIRE_ID
29027#undef DUK__IDX_RESOLVED_ID
29028#undef DUK__IDX_LASTCOMP
29029#undef DUK__IDX_DUKTAPE
29030#undef DUK__IDX_MODLOADED
29031#undef DUK__IDX_UNDEFINED
29032#undef DUK__IDX_FRESH_REQUIRE
29033#undef DUK__IDX_EXPORTS
29034#undef DUK__IDX_MODULE
7c673cae
FG
29035#else
29036DUK_INTERNAL duk_ret_t duk_bi_global_object_require(duk_context *ctx) {
29037 DUK_UNREF(ctx);
29038 return DUK_RET_UNSUPPORTED_ERROR;
29039}
29040#endif /* DUK_USE_COMMONJS_MODULES */
7c673cae
FG
29041/*
29042 * JSON built-ins.
29043 *
29044 * See doc/json.rst.
29045 *
29046 * Codepoints are handled as duk_uint_fast32_t to ensure that the full
29047 * unsigned 32-bit range is supported. This matters to e.g. JX.
29048 *
29049 * Input parsing doesn't do an explicit end-of-input check at all. This is
29050 * safe: input string data is always NUL-terminated (0x00) and valid JSON
29051 * inputs never contain plain NUL characters, so that as long as syntax checks
29052 * are correct, we'll never read past the NUL. This approach reduces code size
29053 * and improves parsing performance, but it's critical that syntax checks are
29054 * indeed correct!
29055 */
29056
29057/* include removed: duk_internal.h */
29058
29059/*
29060 * Local defines and forward declarations.
29061 */
29062
29063#define DUK__JSON_DECSTR_BUFSIZE 128
29064#define DUK__JSON_DECSTR_CHUNKSIZE 64
29065#define DUK__JSON_ENCSTR_CHUNKSIZE 64
29066#define DUK__JSON_STRINGIFY_BUFSIZE 128
29067#define DUK__JSON_MAX_ESC_LEN 10 /* '\Udeadbeef' */
29068
29069DUK_LOCAL_DECL void duk__dec_syntax_error(duk_json_dec_ctx *js_ctx);
29070DUK_LOCAL_DECL void duk__dec_eat_white(duk_json_dec_ctx *js_ctx);
29071DUK_LOCAL_DECL duk_uint8_t duk__dec_peek(duk_json_dec_ctx *js_ctx);
29072DUK_LOCAL_DECL duk_uint8_t duk__dec_get(duk_json_dec_ctx *js_ctx);
29073DUK_LOCAL_DECL duk_uint8_t duk__dec_get_nonwhite(duk_json_dec_ctx *js_ctx);
29074DUK_LOCAL_DECL duk_uint_fast32_t duk__dec_decode_hex_escape(duk_json_dec_ctx *js_ctx, duk_small_uint_t n);
29075DUK_LOCAL_DECL void duk__dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t stridx);
29076DUK_LOCAL_DECL void duk__dec_string(duk_json_dec_ctx *js_ctx);
29077#ifdef DUK_USE_JX
29078DUK_LOCAL_DECL void duk__dec_plain_string(duk_json_dec_ctx *js_ctx);
29079DUK_LOCAL_DECL void duk__dec_pointer(duk_json_dec_ctx *js_ctx);
29080DUK_LOCAL_DECL void duk__dec_buffer(duk_json_dec_ctx *js_ctx);
29081#endif
29082DUK_LOCAL_DECL void duk__dec_number(duk_json_dec_ctx *js_ctx);
29083DUK_LOCAL_DECL void duk__dec_objarr_entry(duk_json_dec_ctx *js_ctx);
29084DUK_LOCAL_DECL void duk__dec_objarr_exit(duk_json_dec_ctx *js_ctx);
29085DUK_LOCAL_DECL void duk__dec_object(duk_json_dec_ctx *js_ctx);
29086DUK_LOCAL_DECL void duk__dec_array(duk_json_dec_ctx *js_ctx);
29087DUK_LOCAL_DECL void duk__dec_value(duk_json_dec_ctx *js_ctx);
29088DUK_LOCAL_DECL void duk__dec_reviver_walk(duk_json_dec_ctx *js_ctx);
29089
29090DUK_LOCAL_DECL void duk__emit_1(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch);
29091DUK_LOCAL_DECL void duk__emit_2(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch1, duk_uint_fast8_t ch2);
7c673cae 29092DUK_LOCAL_DECL void duk__unemit_1(duk_json_enc_ctx *js_ctx);
7c673cae
FG
29093DUK_LOCAL_DECL void duk__emit_hstring(duk_json_enc_ctx *js_ctx, duk_hstring *h);
29094#if defined(DUK_USE_FASTINT)
29095DUK_LOCAL_DECL void duk__emit_cstring(duk_json_enc_ctx *js_ctx, const char *p);
29096#endif
29097DUK_LOCAL_DECL void duk__emit_stridx(duk_json_enc_ctx *js_ctx, duk_small_uint_t stridx);
29098DUK_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);
11fdf7f2 29099DUK_LOCAL_DECL void duk__enc_key_autoquote(duk_json_enc_ctx *js_ctx, duk_hstring *k);
7c673cae 29100DUK_LOCAL_DECL void duk__enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_str);
11fdf7f2
TL
29101DUK_LOCAL_DECL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top);
29102DUK_LOCAL_DECL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top);
7c673cae
FG
29103DUK_LOCAL_DECL void duk__enc_object(duk_json_enc_ctx *js_ctx);
29104DUK_LOCAL_DECL void duk__enc_array(duk_json_enc_ctx *js_ctx);
11fdf7f2 29105DUK_LOCAL_DECL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_holder);
7c673cae
FG
29106DUK_LOCAL_DECL duk_bool_t duk__enc_allow_into_proplist(duk_tval *tv);
29107DUK_LOCAL_DECL void duk__enc_double(duk_json_enc_ctx *js_ctx);
29108#if defined(DUK_USE_FASTINT)
29109DUK_LOCAL_DECL void duk__enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv);
29110#endif
11fdf7f2
TL
29111#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
29112DUK_LOCAL_DECL void duk__enc_buffer(duk_json_enc_ctx *js_ctx, duk_hbuffer *h);
29113DUK_LOCAL_DECL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr);
29114DUK_LOCAL_DECL void duk__enc_bufferobject(duk_json_enc_ctx *js_ctx, duk_hbufferobject *h_bufobj);
29115#endif
29116DUK_LOCAL_DECL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth);
7c673cae
FG
29117
29118/*
29119 * Helper tables
29120 */
29121
29122#if defined(DUK_USE_JSON_QUOTESTRING_FASTPATH)
29123DUK_LOCAL const duk_uint8_t duk__json_quotestr_lookup[256] = {
29124 /* 0x00 ... 0x7f: as is
29125 * 0x80: escape generically
29126 * 0x81: slow path
29127 * 0xa0 ... 0xff: backslash + one char
29128 */
29129
29130 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xe2, 0xf4, 0xee, 0x80, 0xe6, 0xf2, 0x80, 0x80,
29131 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
29132 0x20, 0x21, 0xa2, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
29133 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
29134 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
29135 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0xdc, 0x5d, 0x5e, 0x5f,
29136 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
29137 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x81,
29138 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
29139 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
29140 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
29141 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
29142 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
29143 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
29144 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
29145 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81
29146};
29147#else /* DUK_USE_JSON_QUOTESTRING_FASTPATH */
29148DUK_LOCAL const duk_uint8_t duk__json_quotestr_esc[14] = {
29149 DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL,
29150 DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL,
29151 DUK_ASC_LC_B, DUK_ASC_LC_T, DUK_ASC_LC_N, DUK_ASC_NUL,
29152 DUK_ASC_LC_F, DUK_ASC_LC_R
29153};
29154#endif /* DUK_USE_JSON_QUOTESTRING_FASTPATH */
29155
29156#if defined(DUK_USE_JSON_DECSTRING_FASTPATH)
29157DUK_LOCAL const duk_uint8_t duk__json_decstr_lookup[256] = {
29158 /* 0x00: slow path
29159 * other: as is
29160 */
29161 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29162 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29163 0x20, 0x21, 0x00, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
29164 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
29165 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
29166 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x00, 0x5d, 0x5e, 0x5f,
29167 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
29168 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
29169 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
29170 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
29171 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
29172 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
29173 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
29174 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
29175 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
29176 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
29177};
29178#endif /* DUK_USE_JSON_DECSTRING_FASTPATH */
29179
29180#if defined(DUK_USE_JSON_EATWHITE_FASTPATH)
29181DUK_LOCAL const duk_uint8_t duk__json_eatwhite_lookup[256] = {
29182 /* 0x00: finish (non-white)
29183 * 0x01: continue
29184 */
29185 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
29186 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29187 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29188 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29189 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29190 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29191 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29192 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29193 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29194 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29195 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29196 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29197 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29198 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29199 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29200 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
29201};
29202#endif /* DUK_USE_JSON_EATWHITE_FASTPATH */
29203
29204#if defined(DUK_USE_JSON_DECNUMBER_FASTPATH)
29205DUK_LOCAL const duk_uint8_t duk__json_decnumber_lookup[256] = {
29206 /* 0x00: finish (not part of number)
29207 * 0x01: continue
29208 */
29209 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29210 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29211 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00,
29212 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29213 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29214 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29215 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29216 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29217 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29218 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29219 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29220 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29221 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29222 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29223 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29224 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
29225};
29226#endif /* DUK_USE_JSON_DECNUMBER_FASTPATH */
29227
29228/*
29229 * Parsing implementation.
29230 *
29231 * JSON lexer is now separate from duk_lexer.c because there are numerous
29232 * small differences making it difficult to share the lexer.
29233 *
29234 * The parser here works with raw bytes directly; this works because all
29235 * JSON delimiters are ASCII characters. Invalid xUTF-8 encoded values
29236 * inside strings will be passed on without normalization; this is not a
29237 * compliance concern because compliant inputs will always be valid
29238 * CESU-8 encodings.
29239 */
29240
29241DUK_LOCAL void duk__dec_syntax_error(duk_json_dec_ctx *js_ctx) {
29242 /* Shared handler to minimize parser size. Cause will be
29243 * hidden, unfortunately, but we'll have an offset which
29244 * is often quite enough.
29245 */
11fdf7f2
TL
29246 DUK_ERROR_FMT1(js_ctx->thr, DUK_ERR_SYNTAX_ERROR, DUK_STR_FMT_INVALID_JSON,
29247 (long) (js_ctx->p - js_ctx->p_start));
7c673cae
FG
29248}
29249
29250DUK_LOCAL void duk__dec_eat_white(duk_json_dec_ctx *js_ctx) {
29251 const duk_uint8_t *p;
29252 duk_uint8_t t;
29253
29254 p = js_ctx->p;
29255 for (;;) {
29256 DUK_ASSERT(p <= js_ctx->p_end);
29257 t = *p;
29258
29259#if defined(DUK_USE_JSON_EATWHITE_FASTPATH)
29260 /* This fast path is pretty marginal in practice.
29261 * XXX: candidate for removal.
29262 */
29263 DUK_ASSERT(duk__json_eatwhite_lookup[0x00] == 0x00); /* end-of-input breaks */
29264 if (duk__json_eatwhite_lookup[t] == 0) {
29265 break;
29266 }
29267#else /* DUK_USE_JSON_EATWHITE_FASTPATH */
29268 if (!(t == 0x20 || t == 0x0a || t == 0x0d || t == 0x09)) {
29269 /* NUL also comes here. Comparison order matters, 0x20
29270 * is most common whitespace.
29271 */
29272 break;
29273 }
29274#endif /* DUK_USE_JSON_EATWHITE_FASTPATH */
29275 p++;
29276 }
29277 js_ctx->p = p;
29278}
29279
29280DUK_LOCAL duk_uint8_t duk__dec_peek(duk_json_dec_ctx *js_ctx) {
29281 DUK_ASSERT(js_ctx->p <= js_ctx->p_end);
29282 return *js_ctx->p;
29283}
29284
29285DUK_LOCAL duk_uint8_t duk__dec_get(duk_json_dec_ctx *js_ctx) {
29286 DUK_ASSERT(js_ctx->p <= js_ctx->p_end);
29287 return *js_ctx->p++;
29288}
29289
29290DUK_LOCAL duk_uint8_t duk__dec_get_nonwhite(duk_json_dec_ctx *js_ctx) {
29291 duk__dec_eat_white(js_ctx);
29292 return duk__dec_get(js_ctx);
29293}
29294
29295/* For JX, expressing the whole unsigned 32-bit range matters. */
29296DUK_LOCAL duk_uint_fast32_t duk__dec_decode_hex_escape(duk_json_dec_ctx *js_ctx, duk_small_uint_t n) {
29297 duk_small_uint_t i;
29298 duk_uint_fast32_t res = 0;
29299 duk_uint8_t x;
29300 duk_small_int_t t;
29301
29302 for (i = 0; i < n; i++) {
29303 /* XXX: share helper from lexer; duk_lexer.c / hexval(). */
29304
29305 x = duk__dec_get(js_ctx);
29306 DUK_DDD(DUK_DDDPRINT("decode_hex_escape: i=%ld, n=%ld, res=%ld, x=%ld",
29307 (long) i, (long) n, (long) res, (long) x));
29308
29309 /* x == 0x00 (EOF) causes syntax_error */
29310 DUK_ASSERT(duk_hex_dectab[0] == -1);
29311 t = duk_hex_dectab[x & 0xff];
29312 if (DUK_LIKELY(t >= 0)) {
29313 res = (res * 16) + t;
29314 } else {
29315 /* catches EOF and invalid digits */
29316 goto syntax_error;
29317 }
29318 }
29319
29320 DUK_DDD(DUK_DDDPRINT("final hex decoded value: %ld", (long) res));
29321 return res;
29322
29323 syntax_error:
29324 duk__dec_syntax_error(js_ctx);
29325 DUK_UNREACHABLE();
29326 return 0;
29327}
29328
29329DUK_LOCAL void duk__dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t stridx) {
29330 duk_hstring *h;
11fdf7f2 29331 const duk_uint8_t *p;
7c673cae
FG
29332 duk_uint8_t x, y;
29333
29334 /* First character has already been eaten and checked by the caller.
29335 * We can scan until a NUL in stridx string because no built-in strings
29336 * have internal NULs.
29337 */
29338
29339 DUK_ASSERT_DISABLE(stridx >= 0); /* unsigned */
29340 DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
29341 h = DUK_HTHREAD_GET_STRING(js_ctx->thr, stridx);
29342 DUK_ASSERT(h != NULL);
29343
11fdf7f2 29344 p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h) + 1;
7c673cae
FG
29345 DUK_ASSERT(*(js_ctx->p - 1) == *(p - 1)); /* first character has been matched */
29346
29347 for (;;) {
29348 x = *p;
29349 if (x == 0) {
29350 break;
29351 }
29352 y = duk__dec_get(js_ctx);
29353 if (x != y) {
29354 /* Catches EOF of JSON input. */
29355 goto syntax_error;
29356 }
29357 p++;
29358 }
29359
29360 return;
29361
29362 syntax_error:
29363 duk__dec_syntax_error(js_ctx);
29364 DUK_UNREACHABLE();
29365}
29366
29367DUK_LOCAL duk_small_int_t duk__dec_string_escape(duk_json_dec_ctx *js_ctx, duk_uint8_t **ext_p) {
29368 duk_uint_fast32_t cp;
29369
29370 /* EOF (-1) will be cast to an unsigned value first
29371 * and then re-cast for the switch. In any case, it
29372 * will match the default case (syntax error).
29373 */
29374 cp = (duk_uint_fast32_t) duk__dec_get(js_ctx);
29375 switch ((int) cp) {
29376 case DUK_ASC_BACKSLASH: break;
29377 case DUK_ASC_DOUBLEQUOTE: break;
29378 case DUK_ASC_SLASH: break;
29379 case DUK_ASC_LC_T: cp = 0x09; break;
29380 case DUK_ASC_LC_N: cp = 0x0a; break;
29381 case DUK_ASC_LC_R: cp = 0x0d; break;
29382 case DUK_ASC_LC_F: cp = 0x0c; break;
29383 case DUK_ASC_LC_B: cp = 0x08; break;
29384 case DUK_ASC_LC_U: {
29385 cp = duk__dec_decode_hex_escape(js_ctx, 4);
29386 break;
29387 }
29388#ifdef DUK_USE_JX
29389 case DUK_ASC_UC_U: {
29390 if (js_ctx->flag_ext_custom) {
29391 cp = duk__dec_decode_hex_escape(js_ctx, 8);
29392 } else {
29393 return 1; /* syntax error */
29394 }
29395 break;
29396 }
29397 case DUK_ASC_LC_X: {
29398 if (js_ctx->flag_ext_custom) {
29399 cp = duk__dec_decode_hex_escape(js_ctx, 2);
29400 } else {
29401 return 1; /* syntax error */
29402 }
29403 break;
29404 }
29405#endif /* DUK_USE_JX */
29406 default:
29407 /* catches EOF (0x00) */
29408 return 1; /* syntax error */
29409 }
29410
29411 DUK_RAW_WRITE_XUTF8(*ext_p, cp);
29412
29413 return 0;
29414}
29415
29416DUK_LOCAL void duk__dec_string(duk_json_dec_ctx *js_ctx) {
29417 duk_hthread *thr = js_ctx->thr;
29418 duk_context *ctx = (duk_context *) thr;
29419 duk_bufwriter_ctx bw_alloc;
29420 duk_bufwriter_ctx *bw;
29421 duk_uint8_t *q;
29422
29423 /* '"' was eaten by caller */
29424
29425 /* Note that we currently parse -bytes-, not codepoints.
29426 * All non-ASCII extended UTF-8 will encode to bytes >= 0x80,
29427 * so they'll simply pass through (valid UTF-8 or not).
29428 */
29429
29430 bw = &bw_alloc;
29431 DUK_BW_INIT_PUSHBUF(js_ctx->thr, bw, DUK__JSON_DECSTR_BUFSIZE);
29432 q = DUK_BW_GET_PTR(js_ctx->thr, bw);
29433
29434#if defined(DUK_USE_JSON_DECSTRING_FASTPATH)
29435 for (;;) {
29436 duk_small_uint_t safe;
29437 duk_uint8_t b, x;
29438 const duk_uint8_t *p;
29439
29440 /* Select a safe loop count where no output checks are
29441 * needed assuming we won't encounter escapes. Input
29442 * bound checks are not necessary as a NUL (guaranteed)
29443 * will cause a SyntaxError before we read out of bounds.
29444 */
29445
29446 safe = DUK__JSON_DECSTR_CHUNKSIZE;
29447
29448 /* Ensure space for 1:1 output plus one escape. */
29449 q = DUK_BW_ENSURE_RAW(js_ctx->thr, bw, safe + DUK_UNICODE_MAX_XUTF8_LENGTH, q);
29450
29451 p = js_ctx->p; /* temp copy, write back for next loop */
29452 for (;;) {
29453 if (safe == 0) {
29454 js_ctx->p = p;
29455 break;
29456 }
29457 safe--;
29458
29459 /* End of input (NUL) goes through slow path and causes SyntaxError. */
29460 DUK_ASSERT(duk__json_decstr_lookup[0] == 0x00);
29461
29462 b = *p++;
29463 x = (duk_small_int_t) duk__json_decstr_lookup[b];
29464 if (DUK_LIKELY(x != 0)) {
29465 /* Fast path, decode as is. */
29466 *q++ = b;
29467 } else if (b == DUK_ASC_DOUBLEQUOTE) {
29468 js_ctx->p = p;
29469 goto found_quote;
29470 } else if (b == DUK_ASC_BACKSLASH) {
29471 /* We've ensured space for one escaped input; then
29472 * bail out and recheck (this makes escape handling
29473 * quite slow but it's uncommon).
29474 */
29475 js_ctx->p = p;
29476 if (duk__dec_string_escape(js_ctx, &q) != 0) {
29477 goto syntax_error;
29478 }
29479 break;
29480 } else {
29481 js_ctx->p = p;
29482 goto syntax_error;
29483 }
29484 }
29485 }
29486 found_quote:
29487#else /* DUK_USE_JSON_DECSTRING_FASTPATH */
29488 for (;;) {
29489 duk_uint8_t x;
29490
29491 q = DUK_BW_ENSURE_RAW(js_ctx->thr, bw, DUK_UNICODE_MAX_XUTF8_LENGTH, q);
29492
29493 x = duk__dec_get(js_ctx);
29494
29495 if (x == DUK_ASC_DOUBLEQUOTE) {
29496 break;
29497 } else if (x == DUK_ASC_BACKSLASH) {
29498 if (duk__dec_string_escape(js_ctx, &q) != 0) {
29499 goto syntax_error;
29500 }
29501 } else if (x < 0x20) {
29502 /* catches EOF (NUL) */
29503 goto syntax_error;
29504 } else {
29505 *q++ = (duk_uint8_t) x;
29506 }
29507 }
29508#endif /* DUK_USE_JSON_DECSTRING_FASTPATH */
29509
29510 DUK_BW_SETPTR_AND_COMPACT(js_ctx->thr, bw, q);
29511 duk_to_string(ctx, -1);
29512
29513 /* [ ... str ] */
29514
29515 return;
29516
29517 syntax_error:
29518 duk__dec_syntax_error(js_ctx);
29519 DUK_UNREACHABLE();
29520}
29521
29522#ifdef DUK_USE_JX
29523/* Decode a plain string consisting entirely of identifier characters.
29524 * Used to parse plain keys (e.g. "foo: 123").
29525 */
29526DUK_LOCAL void duk__dec_plain_string(duk_json_dec_ctx *js_ctx) {
29527 duk_hthread *thr = js_ctx->thr;
29528 duk_context *ctx = (duk_context *) thr;
29529 const duk_uint8_t *p;
29530 duk_small_int_t x;
29531
29532 /* Caller has already eaten the first char so backtrack one byte. */
29533
29534 js_ctx->p--; /* safe */
29535 p = js_ctx->p;
29536
29537 /* Here again we parse bytes, and non-ASCII UTF-8 will cause end of
29538 * parsing (which is correct except if there are non-shortest encodings).
29539 * There is also no need to check explicitly for end of input buffer as
29540 * the input is NUL padded and NUL will exit the parsing loop.
29541 *
29542 * Because no unescaping takes place, we can just scan to the end of the
29543 * plain string and intern from the input buffer.
29544 */
29545
29546 for (;;) {
29547 x = *p;
29548
29549 /* There is no need to check the first character specially here
29550 * (i.e. reject digits): the caller only accepts valid initial
29551 * characters and won't call us if the first character is a digit.
29552 * This also ensures that the plain string won't be empty.
29553 */
29554
29555 if (!duk_unicode_is_identifier_part((duk_codepoint_t) x)) {
29556 break;
29557 }
29558 p++;
29559 }
29560
29561 duk_push_lstring(ctx, (const char *) js_ctx->p, (duk_size_t) (p - js_ctx->p));
29562 js_ctx->p = p;
29563
29564 /* [ ... str ] */
29565}
29566#endif /* DUK_USE_JX */
29567
29568#ifdef DUK_USE_JX
29569DUK_LOCAL void duk__dec_pointer(duk_json_dec_ctx *js_ctx) {
29570 duk_hthread *thr = js_ctx->thr;
29571 duk_context *ctx = (duk_context *) thr;
29572 const duk_uint8_t *p;
29573 duk_small_int_t x;
29574 void *voidptr;
29575
29576 /* Caller has already eaten the first character ('(') which we don't need. */
29577
29578 p = js_ctx->p;
29579
29580 for (;;) {
29581 x = *p;
29582
29583 /* Assume that the native representation never contains a closing
29584 * parenthesis.
29585 */
29586
29587 if (x == DUK_ASC_RPAREN) {
29588 break;
29589 } else if (x <= 0) {
29590 /* NUL term or -1 (EOF), NUL check would suffice */
29591 goto syntax_error;
29592 }
29593 p++;
29594 }
29595
29596 /* There is no need to NUL delimit the sscanf() call: trailing garbage is
29597 * ignored and there is always a NUL terminator which will force an error
29598 * if no error is encountered before it. It's possible that the scan
29599 * would scan further than between [js_ctx->p,p[ though and we'd advance
29600 * by less than the scanned value.
29601 *
29602 * Because pointers are platform specific, a failure to scan a pointer
29603 * results in a null pointer which is a better placeholder than a missing
29604 * value or an error.
29605 */
29606
29607 voidptr = NULL;
29608 (void) DUK_SSCANF((const char *) js_ctx->p, DUK_STR_FMT_PTR, &voidptr);
29609 duk_push_pointer(ctx, voidptr);
29610 js_ctx->p = p + 1; /* skip ')' */
29611
29612 /* [ ... ptr ] */
29613
29614 return;
29615
29616 syntax_error:
29617 duk__dec_syntax_error(js_ctx);
29618 DUK_UNREACHABLE();
29619}
29620#endif /* DUK_USE_JX */
29621
29622#ifdef DUK_USE_JX
29623DUK_LOCAL void duk__dec_buffer(duk_json_dec_ctx *js_ctx) {
29624 duk_hthread *thr = js_ctx->thr;
29625 duk_context *ctx = (duk_context *) thr;
29626 const duk_uint8_t *p;
11fdf7f2
TL
29627 duk_uint8_t *buf;
29628 duk_size_t src_len;
7c673cae
FG
29629 duk_small_int_t x;
29630
29631 /* Caller has already eaten the first character ('|') which we don't need. */
29632
29633 p = js_ctx->p;
29634
11fdf7f2
TL
29635 /* XXX: Would be nice to share the fast path loop from duk_hex_decode()
29636 * and avoid creating a temporary buffer. However, there are some
29637 * differences which prevent trivial sharing:
29638 *
29639 * - Pipe char detection
29640 * - EOF detection
29641 * - Unknown length of input and output
29642 *
29643 * The best approach here would be a bufwriter and a reasonaly sized
29644 * safe inner loop (e.g. 64 output bytes at a time).
29645 */
29646
7c673cae
FG
29647 for (;;) {
29648 x = *p;
29649
29650 /* This loop intentionally does not ensure characters are valid
29651 * ([0-9a-fA-F]) because the hex decode call below will do that.
29652 */
29653 if (x == DUK_ASC_PIPE) {
29654 break;
29655 } else if (x <= 0) {
29656 /* NUL term or -1 (EOF), NUL check would suffice */
29657 goto syntax_error;
29658 }
29659 p++;
29660 }
29661
11fdf7f2
TL
29662 src_len = (duk_size_t) (p - js_ctx->p);
29663 buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, src_len);
29664 DUK_ASSERT(buf != NULL);
29665 DUK_MEMCPY((void *) buf, (const void *) js_ctx->p, src_len);
7c673cae 29666 duk_hex_decode(ctx, -1);
11fdf7f2 29667
7c673cae
FG
29668 js_ctx->p = p + 1; /* skip '|' */
29669
29670 /* [ ... buf ] */
29671
29672 return;
29673
29674 syntax_error:
29675 duk__dec_syntax_error(js_ctx);
29676 DUK_UNREACHABLE();
29677}
29678#endif /* DUK_USE_JX */
29679
29680/* Parse a number, other than NaN or +/- Infinity */
29681DUK_LOCAL void duk__dec_number(duk_json_dec_ctx *js_ctx) {
29682 duk_context *ctx = (duk_context *) js_ctx->thr;
29683 const duk_uint8_t *p_start;
29684 const duk_uint8_t *p;
29685 duk_uint8_t x;
29686 duk_small_uint_t s2n_flags;
29687
29688 DUK_DDD(DUK_DDDPRINT("parse_number"));
29689
29690 p_start = js_ctx->p;
29691
29692 /* First pass parse is very lenient (e.g. allows '1.2.3') and extracts a
29693 * string for strict number parsing.
29694 */
29695
29696 p = js_ctx->p;
29697 for (;;) {
29698 x = *p;
29699
29700 DUK_DDD(DUK_DDDPRINT("parse_number: p_start=%p, p=%p, p_end=%p, x=%ld",
11fdf7f2
TL
29701 (const void *) p_start, (const void *) p,
29702 (const void *) js_ctx->p_end, (long) x));
7c673cae
FG
29703
29704#if defined(DUK_USE_JSON_DECNUMBER_FASTPATH)
29705 /* This fast path is pretty marginal in practice.
29706 * XXX: candidate for removal.
29707 */
29708 DUK_ASSERT(duk__json_decnumber_lookup[0x00] == 0x00); /* end-of-input breaks */
29709 if (duk__json_decnumber_lookup[x] == 0) {
29710 break;
29711 }
29712#else /* DUK_USE_JSON_DECNUMBER_FASTPATH */
29713 if (!((x >= DUK_ASC_0 && x <= DUK_ASC_9) ||
29714 (x == DUK_ASC_PERIOD || x == DUK_ASC_LC_E ||
29715 x == DUK_ASC_UC_E || x == DUK_ASC_MINUS || x == DUK_ASC_PLUS))) {
29716 /* Plus sign must be accepted for positive exponents
29717 * (e.g. '1.5e+2'). This clause catches NULs.
29718 */
29719 break;
29720 }
29721#endif /* DUK_USE_JSON_DECNUMBER_FASTPATH */
29722 p++; /* safe, because matched (NUL causes a break) */
29723 }
29724 js_ctx->p = p;
29725
29726 DUK_ASSERT(js_ctx->p > p_start);
29727 duk_push_lstring(ctx, (const char *) p_start, (duk_size_t) (p - p_start));
29728
29729 s2n_flags = DUK_S2N_FLAG_ALLOW_EXP |
29730 DUK_S2N_FLAG_ALLOW_MINUS | /* but don't allow leading plus */
29731 DUK_S2N_FLAG_ALLOW_FRAC;
29732
29733 DUK_DDD(DUK_DDDPRINT("parse_number: string before parsing: %!T",
29734 (duk_tval *) duk_get_tval(ctx, -1)));
29735 duk_numconv_parse(ctx, 10 /*radix*/, s2n_flags);
29736 if (duk_is_nan(ctx, -1)) {
29737 duk__dec_syntax_error(js_ctx);
29738 }
29739 DUK_ASSERT(duk_is_number(ctx, -1));
29740 DUK_DDD(DUK_DDDPRINT("parse_number: final number: %!T",
29741 (duk_tval *) duk_get_tval(ctx, -1)));
29742
29743 /* [ ... num ] */
29744}
29745
29746DUK_LOCAL void duk__dec_objarr_entry(duk_json_dec_ctx *js_ctx) {
29747 duk_context *ctx = (duk_context *) js_ctx->thr;
29748 duk_require_stack(ctx, DUK_JSON_DEC_REQSTACK);
29749
29750 /* c recursion check */
29751
29752 DUK_ASSERT(js_ctx->recursion_depth >= 0);
29753 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
29754 if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
11fdf7f2 29755 DUK_ERROR_RANGE((duk_hthread *) ctx, DUK_STR_JSONDEC_RECLIMIT);
7c673cae
FG
29756 }
29757 js_ctx->recursion_depth++;
29758}
29759
29760DUK_LOCAL void duk__dec_objarr_exit(duk_json_dec_ctx *js_ctx) {
29761 /* c recursion check */
29762
29763 DUK_ASSERT(js_ctx->recursion_depth > 0);
29764 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
29765 js_ctx->recursion_depth--;
29766}
29767
29768DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) {
29769 duk_context *ctx = (duk_context *) js_ctx->thr;
29770 duk_int_t key_count; /* XXX: a "first" flag would suffice */
29771 duk_uint8_t x;
29772
29773 DUK_DDD(DUK_DDDPRINT("parse_object"));
29774
29775 duk__dec_objarr_entry(js_ctx);
29776
29777 duk_push_object(ctx);
29778
29779 /* Initial '{' has been checked and eaten by caller. */
29780
29781 key_count = 0;
29782 for (;;) {
29783 x = duk__dec_get_nonwhite(js_ctx);
29784
29785 DUK_DDD(DUK_DDDPRINT("parse_object: obj=%!T, x=%ld, key_count=%ld",
29786 (duk_tval *) duk_get_tval(ctx, -1),
29787 (long) x, (long) key_count));
29788
29789 /* handle comma and closing brace */
29790
29791 if (x == DUK_ASC_COMMA && key_count > 0) {
29792 /* accept comma, expect new value */
29793 x = duk__dec_get_nonwhite(js_ctx);
29794 } else if (x == DUK_ASC_RCURLY) {
29795 /* eat closing brace */
29796 break;
29797 } else if (key_count == 0) {
29798 /* accept anything, expect first value (EOF will be
29799 * caught by key parsing below.
29800 */
29801 ;
29802 } else {
29803 /* catches EOF (NUL) and initial comma */
29804 goto syntax_error;
29805 }
29806
29807 /* parse key and value */
29808
29809 if (x == DUK_ASC_DOUBLEQUOTE) {
29810 duk__dec_string(js_ctx);
29811#ifdef DUK_USE_JX
29812 } else if (js_ctx->flag_ext_custom &&
29813 duk_unicode_is_identifier_start((duk_codepoint_t) x)) {
29814 duk__dec_plain_string(js_ctx);
29815#endif
29816 } else {
29817 goto syntax_error;
29818 }
29819
29820 /* [ ... obj key ] */
29821
29822 x = duk__dec_get_nonwhite(js_ctx);
29823 if (x != DUK_ASC_COLON) {
29824 goto syntax_error;
29825 }
29826
29827 duk__dec_value(js_ctx);
29828
29829 /* [ ... obj key val ] */
29830
29831 duk_xdef_prop_wec(ctx, -3);
29832
29833 /* [ ... obj ] */
29834
29835 key_count++;
29836 }
29837
29838 /* [ ... obj ] */
29839
29840 DUK_DDD(DUK_DDDPRINT("parse_object: final object is %!T",
29841 (duk_tval *) duk_get_tval(ctx, -1)));
29842
29843 duk__dec_objarr_exit(js_ctx);
29844 return;
29845
29846 syntax_error:
29847 duk__dec_syntax_error(js_ctx);
29848 DUK_UNREACHABLE();
29849}
29850
29851DUK_LOCAL void duk__dec_array(duk_json_dec_ctx *js_ctx) {
29852 duk_context *ctx = (duk_context *) js_ctx->thr;
29853 duk_uarridx_t arr_idx;
29854 duk_uint8_t x;
29855
29856 DUK_DDD(DUK_DDDPRINT("parse_array"));
29857
29858 duk__dec_objarr_entry(js_ctx);
29859
29860 duk_push_array(ctx);
29861
29862 /* Initial '[' has been checked and eaten by caller. */
29863
29864 arr_idx = 0;
29865 for (;;) {
29866 x = duk__dec_get_nonwhite(js_ctx);
29867
29868 DUK_DDD(DUK_DDDPRINT("parse_array: arr=%!T, x=%ld, arr_idx=%ld",
29869 (duk_tval *) duk_get_tval(ctx, -1),
29870 (long) x, (long) arr_idx));
29871
29872 /* handle comma and closing bracket */
29873
29874 if ((x == DUK_ASC_COMMA) && (arr_idx != 0)) {
29875 /* accept comma, expect new value */
29876 ;
29877 } else if (x == DUK_ASC_RBRACKET) {
29878 /* eat closing bracket */
29879 break;
29880 } else if (arr_idx == 0) {
29881 /* accept anything, expect first value (EOF will be
29882 * caught by duk__dec_value() below.
29883 */
29884 js_ctx->p--; /* backtrack (safe) */
29885 } else {
29886 /* catches EOF (NUL) and initial comma */
29887 goto syntax_error;
29888 }
29889
29890 /* parse value */
29891
29892 duk__dec_value(js_ctx);
29893
29894 /* [ ... arr val ] */
29895
29896 duk_xdef_prop_index_wec(ctx, -2, arr_idx);
29897 arr_idx++;
29898 }
29899
29900 /* Must set 'length' explicitly when using duk_xdef_prop_xxx() to
29901 * set the values.
29902 */
29903
29904 duk_set_length(ctx, -1, arr_idx);
29905
29906 /* [ ... arr ] */
29907
29908 DUK_DDD(DUK_DDDPRINT("parse_array: final array is %!T",
29909 (duk_tval *) duk_get_tval(ctx, -1)));
29910
29911 duk__dec_objarr_exit(js_ctx);
29912 return;
29913
29914 syntax_error:
29915 duk__dec_syntax_error(js_ctx);
29916 DUK_UNREACHABLE();
29917}
29918
29919DUK_LOCAL void duk__dec_value(duk_json_dec_ctx *js_ctx) {
29920 duk_context *ctx = (duk_context *) js_ctx->thr;
29921 duk_uint8_t x;
29922
29923 x = duk__dec_get_nonwhite(js_ctx);
29924
29925 DUK_DDD(DUK_DDDPRINT("parse_value: initial x=%ld", (long) x));
29926
29927 /* Note: duk__dec_req_stridx() backtracks one char */
29928
29929 if (x == DUK_ASC_DOUBLEQUOTE) {
29930 duk__dec_string(js_ctx);
29931 } else if ((x >= DUK_ASC_0 && x <= DUK_ASC_9) || (x == DUK_ASC_MINUS)) {
29932#ifdef DUK_USE_JX
29933 if (js_ctx->flag_ext_custom && x == DUK_ASC_MINUS && duk__dec_peek(js_ctx) == DUK_ASC_UC_I) {
29934 duk__dec_req_stridx(js_ctx, DUK_STRIDX_MINUS_INFINITY); /* "-Infinity", '-' has been eaten */
29935 duk_push_number(ctx, -DUK_DOUBLE_INFINITY);
29936 } else {
29937#else
29938 { /* unconditional block */
29939#endif
29940 /* We already ate 'x', so backup one byte. */
29941 js_ctx->p--; /* safe */
29942 duk__dec_number(js_ctx);
29943 }
29944 } else if (x == DUK_ASC_LC_T) {
29945 duk__dec_req_stridx(js_ctx, DUK_STRIDX_TRUE);
29946 duk_push_true(ctx);
29947 } else if (x == DUK_ASC_LC_F) {
29948 duk__dec_req_stridx(js_ctx, DUK_STRIDX_FALSE);
29949 duk_push_false(ctx);
29950 } else if (x == DUK_ASC_LC_N) {
29951 duk__dec_req_stridx(js_ctx, DUK_STRIDX_LC_NULL);
29952 duk_push_null(ctx);
29953#ifdef DUK_USE_JX
29954 } else if (js_ctx->flag_ext_custom && x == DUK_ASC_LC_U) {
29955 duk__dec_req_stridx(js_ctx, DUK_STRIDX_LC_UNDEFINED);
29956 duk_push_undefined(ctx);
29957 } else if (js_ctx->flag_ext_custom && x == DUK_ASC_UC_N) {
29958 duk__dec_req_stridx(js_ctx, DUK_STRIDX_NAN);
29959 duk_push_nan(ctx);
29960 } else if (js_ctx->flag_ext_custom && x == DUK_ASC_UC_I) {
29961 duk__dec_req_stridx(js_ctx, DUK_STRIDX_INFINITY);
29962 duk_push_number(ctx, DUK_DOUBLE_INFINITY);
29963 } else if (js_ctx->flag_ext_custom && x == DUK_ASC_LPAREN) {
29964 duk__dec_pointer(js_ctx);
29965 } else if (js_ctx->flag_ext_custom && x == DUK_ASC_PIPE) {
29966 duk__dec_buffer(js_ctx);
29967#endif
29968 } else if (x == DUK_ASC_LCURLY) {
29969 duk__dec_object(js_ctx);
29970 } else if (x == DUK_ASC_LBRACKET) {
29971 duk__dec_array(js_ctx);
29972 } else {
29973 /* catches EOF (NUL) */
29974 goto syntax_error;
29975 }
29976
29977 duk__dec_eat_white(js_ctx);
29978
29979 /* [ ... val ] */
29980 return;
29981
29982 syntax_error:
29983 duk__dec_syntax_error(js_ctx);
29984 DUK_UNREACHABLE();
29985}
29986
29987/* Recursive value reviver, implements the Walk() algorithm. No C recursion
29988 * check is done here because the initial parsing step will already ensure
29989 * there is a reasonable limit on C recursion depth and hence object depth.
29990 */
29991DUK_LOCAL void duk__dec_reviver_walk(duk_json_dec_ctx *js_ctx) {
29992 duk_context *ctx = (duk_context *) js_ctx->thr;
29993 duk_hobject *h;
29994 duk_uarridx_t i, arr_len;
29995
29996 DUK_DDD(DUK_DDDPRINT("walk: top=%ld, holder=%!T, name=%!T",
29997 (long) duk_get_top(ctx),
29998 (duk_tval *) duk_get_tval(ctx, -2),
29999 (duk_tval *) duk_get_tval(ctx, -1)));
30000
30001 duk_dup_top(ctx);
30002 duk_get_prop(ctx, -3); /* -> [ ... holder name val ] */
30003
30004 h = duk_get_hobject(ctx, -1);
30005 if (h != NULL) {
30006 if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY) {
30007 arr_len = (duk_uarridx_t) duk_get_length(ctx, -1);
30008 for (i = 0; i < arr_len; i++) {
30009 /* [ ... holder name val ] */
30010
30011 DUK_DDD(DUK_DDDPRINT("walk: array, top=%ld, i=%ld, arr_len=%ld, holder=%!T, name=%!T, val=%!T",
30012 (long) duk_get_top(ctx), (long) i, (long) arr_len,
30013 (duk_tval *) duk_get_tval(ctx, -3), (duk_tval *) duk_get_tval(ctx, -2),
30014 (duk_tval *) duk_get_tval(ctx, -1)));
30015
30016 /* XXX: push_uint_string / push_u32_string */
30017 duk_dup_top(ctx);
30018 duk_push_uint(ctx, (duk_uint_t) i);
30019 duk_to_string(ctx, -1); /* -> [ ... holder name val val ToString(i) ] */
30020 duk__dec_reviver_walk(js_ctx); /* -> [ ... holder name val new_elem ] */
30021
30022 if (duk_is_undefined(ctx, -1)) {
30023 duk_pop(ctx);
30024 duk_del_prop_index(ctx, -1, i);
30025 } else {
30026 /* XXX: duk_xdef_prop_index_wec() would be more appropriate
30027 * here but it currently makes some assumptions that might
30028 * not hold (e.g. that previous property is not an accessor).
30029 */
30030 duk_put_prop_index(ctx, -2, i);
30031 }
30032 }
30033 } else {
30034 /* [ ... holder name val ] */
30035 duk_enum(ctx, -1, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/);
30036 while (duk_next(ctx, -1 /*enum_index*/, 0 /*get_value*/)) {
30037 DUK_DDD(DUK_DDDPRINT("walk: object, top=%ld, holder=%!T, name=%!T, val=%!T, enum=%!iT, obj_key=%!T",
30038 (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, -5),
30039 (duk_tval *) duk_get_tval(ctx, -4), (duk_tval *) duk_get_tval(ctx, -3),
30040 (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1)));
30041
30042 /* [ ... holder name val enum obj_key ] */
30043 duk_dup(ctx, -3);
30044 duk_dup(ctx, -2);
30045
30046 /* [ ... holder name val enum obj_key val obj_key ] */
30047 duk__dec_reviver_walk(js_ctx);
30048
30049 /* [ ... holder name val enum obj_key new_elem ] */
30050 if (duk_is_undefined(ctx, -1)) {
30051 duk_pop(ctx);
30052 duk_del_prop(ctx, -3);
30053 } else {
30054 /* XXX: duk_xdef_prop_index_wec() would be more appropriate
30055 * here but it currently makes some assumptions that might
30056 * not hold (e.g. that previous property is not an accessor).
30057 *
30058 * Using duk_put_prop() works incorrectly with '__proto__'
30059 * if the own property with that name has been deleted. This
30060 * does not happen normally, but a clever reviver can trigger
30061 * that, see complex reviver case in: test-bug-json-parse-__proto__.js.
30062 */
30063 duk_put_prop(ctx, -4);
30064 }
30065 }
30066 duk_pop(ctx); /* pop enum */
30067 }
30068 }
30069
30070 /* [ ... holder name val ] */
30071
30072 duk_dup(ctx, js_ctx->idx_reviver);
30073 duk_insert(ctx, -4); /* -> [ ... reviver holder name val ] */
30074 duk_call_method(ctx, 2); /* -> [ ... res ] */
30075
30076 DUK_DDD(DUK_DDDPRINT("walk: top=%ld, result=%!T",
30077 (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, -1)));
30078}
30079
30080/*
30081 * Stringify implementation.
30082 */
30083
30084#define DUK__EMIT_1(js_ctx,ch) duk__emit_1((js_ctx), (duk_uint_fast8_t) (ch))
30085#define DUK__EMIT_2(js_ctx,ch1,ch2) duk__emit_2((js_ctx), (duk_uint_fast8_t) (ch1), (duk_uint_fast8_t) (ch2))
30086#define DUK__EMIT_HSTR(js_ctx,h) duk__emit_hstring((js_ctx), (h))
30087#if defined(DUK_USE_FASTINT) || defined(DUK_USE_JX) || defined(DUK_USE_JC)
30088#define DUK__EMIT_CSTR(js_ctx,p) duk__emit_cstring((js_ctx), (p))
30089#endif
30090#define DUK__EMIT_STRIDX(js_ctx,i) duk__emit_stridx((js_ctx), (i))
7c673cae 30091#define DUK__UNEMIT_1(js_ctx) duk__unemit_1((js_ctx))
7c673cae
FG
30092
30093DUK_LOCAL void duk__emit_1(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch) {
30094 DUK_BW_WRITE_ENSURE_U8(js_ctx->thr, &js_ctx->bw, ch);
30095}
30096
30097DUK_LOCAL void duk__emit_2(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch1, duk_uint_fast8_t ch2) {
30098 DUK_BW_WRITE_ENSURE_U8_2(js_ctx->thr, &js_ctx->bw, ch1, ch2);
30099}
30100
30101DUK_LOCAL void duk__emit_hstring(duk_json_enc_ctx *js_ctx, duk_hstring *h) {
30102 DUK_BW_WRITE_ENSURE_HSTRING(js_ctx->thr, &js_ctx->bw, h);
30103}
30104
30105#if defined(DUK_USE_FASTINT) || defined(DUK_USE_JX) || defined(DUK_USE_JC)
30106DUK_LOCAL void duk__emit_cstring(duk_json_enc_ctx *js_ctx, const char *str) {
30107 DUK_BW_WRITE_ENSURE_CSTRING(js_ctx->thr, &js_ctx->bw, str);
30108}
30109#endif
30110
30111DUK_LOCAL void duk__emit_stridx(duk_json_enc_ctx *js_ctx, duk_small_uint_t stridx) {
30112 duk_hstring *h;
30113
30114 DUK_ASSERT_DISABLE(stridx >= 0); /* unsigned */
30115 DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
30116 h = DUK_HTHREAD_GET_STRING(js_ctx->thr, stridx);
30117 DUK_ASSERT(h != NULL);
30118
30119 DUK_BW_WRITE_ENSURE_HSTRING(js_ctx->thr, &js_ctx->bw, h);
30120}
30121
7c673cae
FG
30122DUK_LOCAL void duk__unemit_1(duk_json_enc_ctx *js_ctx) {
30123 DUK_ASSERT(DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw) >= 1);
30124 DUK_BW_ADD_PTR(js_ctx->thr, &js_ctx->bw, -1);
30125}
7c673cae
FG
30126
30127#define DUK__MKESC(nybbles,esc1,esc2) \
30128 (((duk_uint_fast32_t) (nybbles)) << 16) | \
30129 (((duk_uint_fast32_t) (esc1)) << 8) | \
30130 ((duk_uint_fast32_t) (esc2))
30131
30132DUK_LOCAL duk_uint8_t *duk__emit_esc_auto_fast(duk_json_enc_ctx *js_ctx, duk_uint_fast32_t cp, duk_uint8_t *q) {
30133 duk_uint_fast32_t tmp;
30134 duk_small_uint_t dig;
30135
30136 DUK_UNREF(js_ctx);
30137
30138 /* Caller ensures space for at least DUK__JSON_MAX_ESC_LEN. */
30139
30140 /* Select appropriate escape format automatically, and set 'tmp' to a
30141 * value encoding both the escape format character and the nybble count:
30142 *
30143 * (nybble_count << 16) | (escape_char1) | (escape_char2)
30144 */
30145
30146#ifdef DUK_USE_JX
30147 if (DUK_LIKELY(cp < 0x100UL)) {
30148 if (DUK_UNLIKELY(js_ctx->flag_ext_custom)) {
30149 tmp = DUK__MKESC(2, DUK_ASC_BACKSLASH, DUK_ASC_LC_X);
30150 } else {
30151 tmp = DUK__MKESC(4, DUK_ASC_BACKSLASH, DUK_ASC_LC_U);
30152 }
30153 } else
30154#endif
30155 if (DUK_LIKELY(cp < 0x10000UL)) {
30156 tmp = DUK__MKESC(4, DUK_ASC_BACKSLASH, DUK_ASC_LC_U);
30157 } else {
30158#ifdef DUK_USE_JX
30159 if (DUK_LIKELY(js_ctx->flag_ext_custom)) {
30160 tmp = DUK__MKESC(8, DUK_ASC_BACKSLASH, DUK_ASC_UC_U);
30161 } else
30162#endif
30163 {
30164 /* In compatible mode and standard JSON mode, output
30165 * something useful for non-BMP characters. This won't
30166 * roundtrip but will still be more or less readable and
30167 * more useful than an error.
30168 */
30169 tmp = DUK__MKESC(8, DUK_ASC_UC_U, DUK_ASC_PLUS);
30170 }
30171 }
30172
30173 *q++ = (duk_uint8_t) ((tmp >> 8) & 0xff);
30174 *q++ = (duk_uint8_t) (tmp & 0xff);
30175
30176 tmp = tmp >> 16;
30177 while (tmp > 0) {
30178 tmp--;
30179 dig = (duk_small_uint_t) ((cp >> (4 * tmp)) & 0x0f);
30180 *q++ = duk_lc_digits[dig];
30181 }
30182
30183 return q;
30184}
30185
11fdf7f2
TL
30186DUK_LOCAL void duk__enc_key_autoquote(duk_json_enc_ctx *js_ctx, duk_hstring *k) {
30187 const duk_int8_t *p, *p_start, *p_end; /* Note: intentionally signed. */
30188 duk_size_t k_len;
30189 duk_codepoint_t cp;
7c673cae 30190
11fdf7f2 30191 DUK_ASSERT(k != NULL);
7c673cae 30192
11fdf7f2
TL
30193 /* Accept ASCII strings which conform to identifier requirements
30194 * as being emitted without key quotes. Since we only accept ASCII
30195 * there's no need for actual decoding: 'p' is intentionally signed
30196 * so that bytes >= 0x80 extend to negative values and are rejected
30197 * as invalid identifier codepoints.
7c673cae
FG
30198 */
30199
11fdf7f2
TL
30200 if (js_ctx->flag_avoid_key_quotes) {
30201 k_len = DUK_HSTRING_GET_BYTELEN(k);
30202 p_start = (const duk_int8_t *) DUK_HSTRING_GET_DATA(k);
30203 p_end = p_start + k_len;
30204 p = p_start;
7c673cae 30205
11fdf7f2
TL
30206 if (p == p_end) {
30207 /* Zero length string is not accepted without quotes */
30208 goto quote_normally;
30209 }
30210 cp = (duk_codepoint_t) (*p++);
30211 if (DUK_UNLIKELY(!duk_unicode_is_identifier_start(cp))) {
30212 goto quote_normally;
30213 }
30214 while (p < p_end) {
30215 cp = (duk_codepoint_t) (*p++);
30216 if (DUK_UNLIKELY(!duk_unicode_is_identifier_part(cp))) {
30217 goto quote_normally;
30218 }
7c673cae
FG
30219 }
30220
11fdf7f2
TL
30221 /* This seems faster than emitting bytes one at a time and
30222 * then potentially rewinding.
30223 */
30224 DUK__EMIT_HSTR(js_ctx, k);
30225 return;
7c673cae
FG
30226 }
30227
11fdf7f2
TL
30228 quote_normally:
30229 duk__enc_quote_string(js_ctx, k);
7c673cae
FG
30230}
30231
30232/* The Quote(value) operation: quote a string.
30233 *
30234 * Stack policy: [ ] -> [ ].
30235 */
30236
30237DUK_LOCAL void duk__enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_str) {
30238 duk_hthread *thr = js_ctx->thr;
30239 const duk_uint8_t *p, *p_start, *p_end, *p_now, *p_tmp;
30240 duk_uint8_t *q;
30241 duk_ucodepoint_t cp; /* typed for duk_unicode_decode_xutf8() */
30242
30243 DUK_DDD(DUK_DDDPRINT("duk__enc_quote_string: h_str=%!O", (duk_heaphdr *) h_str));
30244
30245 DUK_ASSERT(h_str != NULL);
30246 p_start = DUK_HSTRING_GET_DATA(h_str);
30247 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_str);
30248 p = p_start;
30249
30250 DUK__EMIT_1(js_ctx, DUK_ASC_DOUBLEQUOTE);
30251
30252 /* Encode string in small chunks, estimating the maximum expansion so that
30253 * there's no need to ensure space while processing the chunk.
30254 */
30255
30256 while (p < p_end) {
30257 duk_size_t left, now, space;
30258
30259 left = (duk_size_t) (p_end - p);
30260 now = (left > DUK__JSON_ENCSTR_CHUNKSIZE ?
30261 DUK__JSON_ENCSTR_CHUNKSIZE : left);
30262
30263 /* Maximum expansion per input byte is 6:
30264 * - invalid UTF-8 byte causes "\uXXXX" to be emitted (6/1 = 6).
30265 * - 2-byte UTF-8 encodes as "\uXXXX" (6/2 = 3).
30266 * - 4-byte UTF-8 encodes as "\Uxxxxxxxx" (10/4 = 2.5).
30267 */
30268 space = now * 6;
30269 q = DUK_BW_ENSURE_GETPTR(thr, &js_ctx->bw, space);
30270
30271 p_now = p + now;
30272
30273 while (p < p_now) {
30274#if defined(DUK_USE_JSON_QUOTESTRING_FASTPATH)
30275 duk_uint8_t b;
30276
30277 b = duk__json_quotestr_lookup[*p++];
30278 if (DUK_LIKELY(b < 0x80)) {
30279 /* Most input bytes go through here. */
30280 *q++ = b;
30281 } else if (b >= 0xa0) {
30282 *q++ = DUK_ASC_BACKSLASH;
30283 *q++ = (duk_uint8_t) (b - 0x80);
30284 } else if (b == 0x80) {
30285 cp = (duk_ucodepoint_t) (*(p - 1));
30286 q = duk__emit_esc_auto_fast(js_ctx, cp, q);
30287 } else if (b == 0x7f && js_ctx->flag_ascii_only) {
30288 /* 0x7F is special */
30289 DUK_ASSERT(b == 0x81);
30290 cp = (duk_ucodepoint_t) 0x7f;
30291 q = duk__emit_esc_auto_fast(js_ctx, cp, q);
30292 } else {
30293 DUK_ASSERT(b == 0x81);
30294 p--;
30295
30296 /* slow path is shared */
30297#else /* DUK_USE_JSON_QUOTESTRING_FASTPATH */
30298 cp = *p;
30299
30300 if (DUK_LIKELY(cp <= 0x7f)) {
30301 /* ascii fast path: avoid decoding utf-8 */
30302 p++;
30303 if (cp == 0x22 || cp == 0x5c) {
30304 /* double quote or backslash */
30305 *q++ = DUK_ASC_BACKSLASH;
30306 *q++ = (duk_uint8_t) cp;
30307 } else if (cp < 0x20) {
30308 duk_uint_fast8_t esc_char;
30309
30310 /* This approach is a bit shorter than a straight
30311 * if-else-ladder and also a bit faster.
30312 */
30313 if (cp < (sizeof(duk__json_quotestr_esc) / sizeof(duk_uint8_t)) &&
30314 (esc_char = duk__json_quotestr_esc[cp]) != 0) {
30315 *q++ = DUK_ASC_BACKSLASH;
30316 *q++ = (duk_uint8_t) esc_char;
30317 } else {
30318 q = duk__emit_esc_auto_fast(js_ctx, cp, q);
30319 }
30320 } else if (cp == 0x7f && js_ctx->flag_ascii_only) {
30321 q = duk__emit_esc_auto_fast(js_ctx, cp, q);
30322 } else {
30323 /* any other printable -> as is */
30324 *q++ = (duk_uint8_t) cp;
30325 }
30326 } else {
30327 /* slow path is shared */
30328#endif /* DUK_USE_JSON_QUOTESTRING_FASTPATH */
30329
30330 /* slow path decode */
30331
30332 /* If XUTF-8 decoding fails, treat the offending byte as a codepoint directly
30333 * and go forward one byte. This is of course very lossy, but allows some kind
30334 * of output to be produced even for internal strings which don't conform to
30335 * XUTF-8. All standard Ecmascript strings are always CESU-8, so this behavior
30336 * does not violate the Ecmascript specification. The behavior is applied to
30337 * all modes, including Ecmascript standard JSON. Because the current XUTF-8
30338 * decoding is not very strict, this behavior only really affects initial bytes
30339 * and truncated codepoints.
30340 *
30341 * Another alternative would be to scan forwards to start of next codepoint
30342 * (or end of input) and emit just one replacement codepoint.
30343 */
30344
30345 p_tmp = p;
30346 if (!duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp)) {
30347 /* Decode failed. */
30348 cp = *p_tmp;
30349 p = p_tmp + 1;
30350 }
30351
30352#ifdef DUK_USE_NONSTD_JSON_ESC_U2028_U2029
30353 if (js_ctx->flag_ascii_only || cp == 0x2028 || cp == 0x2029) {
30354#else
30355 if (js_ctx->flag_ascii_only) {
30356#endif
30357 q = duk__emit_esc_auto_fast(js_ctx, cp, q);
30358 } else {
30359 /* as is */
30360 DUK_RAW_WRITE_XUTF8(q, cp);
30361 }
30362 }
30363 }
30364
30365 DUK_BW_SET_PTR(thr, &js_ctx->bw, q);
30366 }
30367
30368 DUK__EMIT_1(js_ctx, DUK_ASC_DOUBLEQUOTE);
30369}
30370
30371/* Encode a double (checked by caller) from stack top. Stack top may be
30372 * replaced by serialized string but is not popped (caller does that).
30373 */
30374DUK_LOCAL void duk__enc_double(duk_json_enc_ctx *js_ctx) {
11fdf7f2 30375 duk_hthread *thr;
7c673cae
FG
30376 duk_context *ctx;
30377 duk_tval *tv;
30378 duk_double_t d;
30379 duk_small_int_t c;
30380 duk_small_int_t s;
30381 duk_small_uint_t stridx;
30382 duk_small_uint_t n2s_flags;
30383 duk_hstring *h_str;
30384
30385 DUK_ASSERT(js_ctx != NULL);
11fdf7f2
TL
30386 thr = js_ctx->thr;
30387 DUK_ASSERT(thr != NULL);
30388 ctx = (duk_context *) thr;
7c673cae
FG
30389
30390 /* Caller must ensure 'tv' is indeed a double and not a fastint! */
11fdf7f2 30391 tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
7c673cae
FG
30392 DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
30393 d = DUK_TVAL_GET_DOUBLE(tv);
30394
30395 c = (duk_small_int_t) DUK_FPCLASSIFY(d);
30396 s = (duk_small_int_t) DUK_SIGNBIT(d);
30397 DUK_UNREF(s);
30398
30399 if (DUK_LIKELY(!(c == DUK_FP_INFINITE || c == DUK_FP_NAN))) {
30400 DUK_ASSERT(DUK_ISFINITE(d));
30401
30402#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
30403 /* Negative zero needs special handling in JX/JC because
30404 * it would otherwise serialize to '0', not '-0'.
30405 */
30406 if (DUK_UNLIKELY(c == DUK_FP_ZERO && s != 0 &&
11fdf7f2 30407 (js_ctx->flag_ext_custom_or_compatible))) {
7c673cae
FG
30408 duk_push_hstring_stridx(ctx, DUK_STRIDX_MINUS_ZERO); /* '-0' */
30409 } else
30410#endif /* DUK_USE_JX || DUK_USE_JC */
30411 {
30412 n2s_flags = 0;
30413 /* [ ... number ] -> [ ... string ] */
30414 duk_numconv_stringify(ctx, 10 /*radix*/, 0 /*digits*/, n2s_flags);
30415 }
30416 h_str = duk_to_hstring(ctx, -1);
30417 DUK_ASSERT(h_str != NULL);
30418 DUK__EMIT_HSTR(js_ctx, h_str);
30419 return;
30420 }
30421
30422#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
30423 if (!(js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM |
30424 DUK_JSON_FLAG_EXT_COMPATIBLE))) {
30425 stridx = DUK_STRIDX_LC_NULL;
30426 } else if (c == DUK_FP_NAN) {
30427 stridx = js_ctx->stridx_custom_nan;
30428 } else if (s == 0) {
30429 stridx = js_ctx->stridx_custom_posinf;
30430 } else {
30431 stridx = js_ctx->stridx_custom_neginf;
30432 }
30433#else
30434 stridx = DUK_STRIDX_LC_NULL;
30435#endif
30436 DUK__EMIT_STRIDX(js_ctx, stridx);
30437}
30438
30439#if defined(DUK_USE_FASTINT)
30440/* Encode a fastint from duk_tval ptr, no value stack effects. */
30441DUK_LOCAL void duk__enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv) {
30442 duk_int64_t v;
30443
30444 /* Fastint range is signed 48-bit so longest value is -2^47 = -140737488355328
30445 * (16 chars long), longest signed 64-bit value is -2^63 = -9223372036854775808
30446 * (20 chars long). Alloc space for 64-bit range to be safe.
30447 */
30448 duk_uint8_t buf[20 + 1];
30449
30450 /* Caller must ensure 'tv' is indeed a fastint! */
30451 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv));
30452 v = DUK_TVAL_GET_FASTINT(tv);
30453
30454 /* XXX: There are no format strings in duk_config.h yet, could add
30455 * one for formatting duk_int64_t. For now, assumes "%lld" and that
30456 * "long long" type exists. Could also rely on C99 directly but that
30457 * won't work for older MSVC.
30458 */
30459 DUK_SPRINTF((char *) buf, "%lld", (long long) v);
30460 DUK__EMIT_CSTR(js_ctx, (const char *) buf);
30461}
30462#endif
30463
11fdf7f2
TL
30464#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
30465#if defined(DUK_USE_HEX_FASTPATH)
30466DUK_LOCAL duk_uint8_t *duk__enc_buffer_data_hex(const duk_uint8_t *src, duk_size_t src_len, duk_uint8_t *dst) {
30467 duk_uint8_t *q;
30468 duk_uint16_t *q16;
30469 duk_small_uint_t x;
30470 duk_size_t i, len_safe;
30471#if !defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE)
30472 duk_bool_t shift_dst;
30473#endif
30474
30475 /* Unlike in duk_hex_encode() 'dst' is not necessarily aligned by 2.
30476 * For platforms where unaligned accesses are not allowed, shift 'dst'
30477 * ahead by 1 byte to get alignment and then DUK_MEMMOVE() the result
30478 * in place. The faster encoding loop makes up the difference.
30479 * There's always space for one extra byte because a terminator always
30480 * follows the hex data and that's been accounted for by the caller.
30481 */
30482
30483#if defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE)
30484 q16 = (duk_uint16_t *) (void *) dst;
30485#else
30486 shift_dst = (duk_bool_t) (((duk_size_t) dst) & 0x01U);
30487 if (shift_dst) {
30488 DUK_DD(DUK_DDPRINT("unaligned accesses not possible, dst not aligned -> step to dst + 1"));
30489 q16 = (duk_uint16_t *) (void *) (dst + 1);
30490 } else {
30491 DUK_DD(DUK_DDPRINT("unaligned accesses not possible, dst is aligned"));
30492 q16 = (duk_uint16_t *) (void *) dst;
30493 }
30494 DUK_ASSERT((((duk_size_t) q16) & 0x01U) == 0);
30495#endif
30496
30497 len_safe = src_len & ~0x03U;
30498 for (i = 0; i < len_safe; i += 4) {
30499 q16[0] = duk_hex_enctab[src[i]];
30500 q16[1] = duk_hex_enctab[src[i + 1]];
30501 q16[2] = duk_hex_enctab[src[i + 2]];
30502 q16[3] = duk_hex_enctab[src[i + 3]];
30503 q16 += 4;
30504 }
30505 q = (duk_uint8_t *) q16;
30506
30507#if !defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE)
30508 if (shift_dst) {
30509 q--;
30510 DUK_MEMMOVE((void *) dst, (const void *) (dst + 1), 2 * len_safe);
30511 DUK_ASSERT(dst + 2 * len_safe == q);
30512 }
30513#endif
30514
30515 for (; i < src_len; i++) {
30516 x = src[i];
30517 *q++ = duk_lc_digits[x >> 4];
30518 *q++ = duk_lc_digits[x & 0x0f];
30519 }
30520
30521 return q;
30522}
30523#else /* DUK_USE_HEX_FASTPATH */
30524DUK_LOCAL duk_uint8_t *duk__enc_buffer_data_hex(const duk_uint8_t *src, duk_size_t src_len, duk_uint8_t *dst) {
30525 const duk_uint8_t *p;
30526 const duk_uint8_t *p_end;
30527 duk_uint8_t *q;
30528 duk_small_uint_t x;
30529
30530 p = src;
30531 p_end = src + src_len;
30532 q = dst;
30533 while (p != p_end) {
30534 x = *p++;
30535 *q++ = duk_lc_digits[x >> 4];
30536 *q++ = duk_lc_digits[x & 0x0f];
30537 }
30538
30539 return q;
30540}
30541#endif /* DUK_USE_HEX_FASTPATH */
30542
30543DUK_LOCAL void duk__enc_buffer_data(duk_json_enc_ctx *js_ctx, duk_uint8_t *buf_data, duk_size_t buf_len) {
30544 duk_hthread *thr;
30545 duk_uint8_t *q;
30546 duk_size_t space;
30547
30548 thr = js_ctx->thr;
30549
30550 DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); /* caller checks */
30551 DUK_ASSERT(js_ctx->flag_ext_custom_or_compatible);
30552
30553 /* Buffer values are encoded in (lowercase) hex to make the
30554 * binary data readable. Base64 or similar would be more
30555 * compact but less readable, and the point of JX/JC
30556 * variants is to be as useful to a programmer as possible.
30557 */
30558
30559 /* The #ifdef clutter here needs to handle the three cases:
30560 * (1) JX+JC, (2) JX only, (3) JC only.
30561 */
30562
30563 /* Note: space must cater for both JX and JC. */
30564 space = 9 + buf_len * 2 + 2;
30565 DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN <= 0x7ffffffeUL);
30566 DUK_ASSERT((space - 2) / 2 >= buf_len); /* overflow not possible, buffer limits */
30567 q = DUK_BW_ENSURE_GETPTR(thr, &js_ctx->bw, space);
30568
30569#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
30570 if (js_ctx->flag_ext_custom)
30571#endif
30572#if defined(DUK_USE_JX)
30573 {
30574 *q++ = DUK_ASC_PIPE;
30575 q = duk__enc_buffer_data_hex(buf_data, buf_len, q);
30576 *q++ = DUK_ASC_PIPE;
30577
30578 }
30579#endif
30580#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
30581 else
30582#endif
30583#if defined(DUK_USE_JC)
30584 {
30585 DUK_ASSERT(js_ctx->flag_ext_compatible);
30586 DUK_MEMCPY((void *) q, (const void *) "{\"_buf\":\"", 9); /* len: 9 */
30587 q += 9;
30588 q = duk__enc_buffer_data_hex(buf_data, buf_len, q);
30589 *q++ = DUK_ASC_DOUBLEQUOTE;
30590 *q++ = DUK_ASC_RCURLY;
30591 }
30592#endif
30593
30594 DUK_BW_SET_PTR(thr, &js_ctx->bw, q);
30595}
30596
30597DUK_LOCAL void duk__enc_buffer(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) {
30598 duk__enc_buffer_data(js_ctx,
30599 (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(js_ctx->thr->heap, h),
30600 (duk_size_t) DUK_HBUFFER_GET_SIZE(h));
30601}
30602#endif /* DUK_USE_JX || DUK_USE_JC */
30603
30604#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
30605DUK_LOCAL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr) {
30606 char buf[64]; /* XXX: how to figure correct size? */
30607 const char *fmt;
30608
30609 DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); /* caller checks */
30610 DUK_ASSERT(js_ctx->flag_ext_custom_or_compatible);
30611
30612 DUK_MEMZERO(buf, sizeof(buf));
30613
30614 /* The #ifdef clutter here needs to handle the three cases:
30615 * (1) JX+JC, (2) JX only, (3) JC only.
30616 */
30617#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
30618 if (js_ctx->flag_ext_custom)
30619#endif
30620#if defined(DUK_USE_JX)
30621 {
30622 fmt = ptr ? "(%p)" : "(null)";
30623 }
30624#endif
30625#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
30626 else
30627#endif
30628#if defined(DUK_USE_JC)
30629 {
30630 DUK_ASSERT(js_ctx->flag_ext_compatible);
30631 fmt = ptr ? "{\"_ptr\":\"%p\"}" : "{\"_ptr\":\"null\"}";
30632 }
30633#endif
30634
30635 /* When ptr == NULL, the format argument is unused. */
30636 DUK_SNPRINTF(buf, sizeof(buf) - 1, fmt, ptr); /* must not truncate */
30637 DUK__EMIT_CSTR(js_ctx, buf);
30638}
30639#endif /* DUK_USE_JX || DUK_USE_JC */
30640
30641#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
30642DUK_LOCAL void duk__enc_bufferobject(duk_json_enc_ctx *js_ctx, duk_hbufferobject *h_bufobj) {
30643 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
30644
30645 if (h_bufobj->buf == NULL || !DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj)) {
30646 DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
30647 } else {
30648 /* Handle both full and partial slice (as long as covered). */
30649 duk__enc_buffer_data(js_ctx,
30650 (duk_uint8_t *) DUK_HBUFFEROBJECT_GET_SLICE_BASE(js_ctx->thr->heap, h_bufobj),
30651 (duk_size_t) h_bufobj->length);
30652 }
30653}
30654#endif /* DUK_USE_JX || DUK_USE_JC */
30655
30656/* Indent helper. Calling code relies on js_ctx->recursion_depth also being
30657 * directly related to indent depth.
7c673cae 30658 */
11fdf7f2
TL
30659#if defined(DUK_USE_PREFER_SIZE)
30660DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth) {
30661 DUK_ASSERT(js_ctx->h_gap != NULL);
30662 DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) > 0); /* caller guarantees */
30663
30664 DUK__EMIT_1(js_ctx, 0x0a);
30665 while (depth-- > 0) {
30666 DUK__EMIT_HSTR(js_ctx, js_ctx->h_gap);
30667 }
30668}
30669#else /* DUK_USE_PREFER_SIZE */
30670DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth) {
30671 const duk_uint8_t *gap_data;
30672 duk_size_t gap_len;
30673 duk_size_t avail_bytes; /* bytes of indent available for copying */
30674 duk_size_t need_bytes; /* bytes of indent still needed */
30675 duk_uint8_t *p_start;
30676 duk_uint8_t *p;
30677
30678 DUK_ASSERT(js_ctx->h_gap != NULL);
30679 DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) > 0); /* caller guarantees */
30680
30681 DUK__EMIT_1(js_ctx, 0x0a);
30682 if (DUK_UNLIKELY(depth == 0)) {
30683 return;
30684 }
30685
30686 /* To handle deeper indents efficiently, make use of copies we've
30687 * already emitted. In effect we can emit a sequence of 1, 2, 4,
30688 * 8, etc copies, and then finish the last run. Byte counters
30689 * avoid multiply with gap_len on every loop.
30690 */
30691
30692 gap_data = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(js_ctx->h_gap);
30693 gap_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap);
30694 DUK_ASSERT(gap_len > 0);
30695
30696 need_bytes = gap_len * depth;
30697 p = DUK_BW_ENSURE_GETPTR(js_ctx->thr, &js_ctx->bw, need_bytes);
30698 p_start = p;
30699
30700 DUK_MEMCPY((void *) p, (const void *) gap_data, (size_t) gap_len);
30701 p += gap_len;
30702 avail_bytes = gap_len;
30703 DUK_ASSERT(need_bytes >= gap_len);
30704 need_bytes -= gap_len;
30705
30706 while (need_bytes >= avail_bytes) {
30707 DUK_MEMCPY((void *) p, (const void *) p_start, (size_t) avail_bytes);
30708 p += avail_bytes;
30709 need_bytes -= avail_bytes;
30710 avail_bytes <<= 1;
30711 }
30712
30713 DUK_ASSERT(need_bytes < avail_bytes); /* need_bytes may be zero */
30714 DUK_MEMCPY((void *) p, (const void *) p_start, (size_t) need_bytes);
30715 p += need_bytes;
30716 /*avail_bytes += need_bytes*/
30717
30718 DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, p);
30719}
30720#endif /* DUK_USE_PREFER_SIZE */
30721
30722/* Shared entry handling for object/array serialization. */
30723DUK_LOCAL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) {
7c673cae
FG
30724 duk_context *ctx = (duk_context *) js_ctx->thr;
30725 duk_hobject *h_target;
11fdf7f2 30726 duk_uint_fast32_t i, n;
7c673cae
FG
30727
30728 *entry_top = duk_get_top(ctx);
30729
30730 duk_require_stack(ctx, DUK_JSON_ENC_REQSTACK);
30731
11fdf7f2
TL
30732 /* Loop check using a hybrid approach: a fixed-size visited[] array
30733 * with overflow in a loop check object.
30734 */
7c673cae
FG
30735
30736 h_target = duk_get_hobject(ctx, -1); /* object or array */
30737 DUK_ASSERT(h_target != NULL);
30738
11fdf7f2
TL
30739 n = js_ctx->recursion_depth;
30740 if (DUK_UNLIKELY(n > DUK_JSON_ENC_LOOPARRAY)) {
30741 n = DUK_JSON_ENC_LOOPARRAY;
30742 }
30743 for (i = 0; i < n; i++) {
30744 if (DUK_UNLIKELY(js_ctx->visiting[i] == h_target)) {
30745 DUK_DD(DUK_DDPRINT("slow path loop detect"));
30746 DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_CYCLIC_INPUT);
30747 }
30748 }
30749 if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) {
30750 js_ctx->visiting[js_ctx->recursion_depth] = h_target;
30751 } else {
30752 duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) h_target);
30753 duk_dup_top(ctx); /* -> [ ... voidp voidp ] */
30754 if (duk_has_prop(ctx, js_ctx->idx_loop)) {
30755 DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_CYCLIC_INPUT);
30756 }
30757 duk_push_true(ctx); /* -> [ ... voidp true ] */
30758 duk_put_prop(ctx, js_ctx->idx_loop); /* -> [ ... ] */
7c673cae 30759 }
7c673cae 30760
11fdf7f2 30761 /* C recursion check. */
7c673cae
FG
30762
30763 DUK_ASSERT(js_ctx->recursion_depth >= 0);
30764 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
30765 if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
11fdf7f2 30766 DUK_ERROR_RANGE((duk_hthread *) ctx, DUK_STR_JSONENC_RECLIMIT);
7c673cae
FG
30767 }
30768 js_ctx->recursion_depth++;
30769
7c673cae
FG
30770 DUK_DDD(DUK_DDDPRINT("shared entry finished: top=%ld, loop=%!T",
30771 (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop)));
30772}
30773
30774/* Shared exit handling for object/array serialization. */
11fdf7f2 30775DUK_LOCAL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) {
7c673cae
FG
30776 duk_context *ctx = (duk_context *) js_ctx->thr;
30777 duk_hobject *h_target;
30778
11fdf7f2 30779 /* C recursion check. */
7c673cae
FG
30780
30781 DUK_ASSERT(js_ctx->recursion_depth > 0);
30782 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
30783 js_ctx->recursion_depth--;
30784
11fdf7f2 30785 /* Loop check. */
7c673cae
FG
30786
30787 h_target = duk_get_hobject(ctx, *entry_top - 1); /* original target at entry_top - 1 */
30788 DUK_ASSERT(h_target != NULL);
30789
11fdf7f2
TL
30790 if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) {
30791 /* Previous entry was inside visited[], nothing to do. */
30792 } else {
30793 duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) h_target);
30794 duk_del_prop(ctx, js_ctx->idx_loop); /* -> [ ... ] */
30795 }
7c673cae 30796
11fdf7f2 30797 /* Restore stack top after unbalanced code paths. */
7c673cae
FG
30798 duk_set_top(ctx, *entry_top);
30799
30800 DUK_DDD(DUK_DDDPRINT("shared entry finished: top=%ld, loop=%!T",
30801 (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop)));
30802}
30803
30804/* The JO(value) operation: encode object.
30805 *
30806 * Stack policy: [ object ] -> [ object ].
30807 */
30808DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
30809 duk_context *ctx = (duk_context *) js_ctx->thr;
7c673cae
FG
30810 duk_hstring *h_key;
30811 duk_idx_t entry_top;
30812 duk_idx_t idx_obj;
30813 duk_idx_t idx_keys;
11fdf7f2 30814 duk_bool_t emitted;
7c673cae 30815 duk_uarridx_t arr_len, i;
11fdf7f2 30816 duk_size_t prev_size;
7c673cae
FG
30817
30818 DUK_DDD(DUK_DDDPRINT("duk__enc_object: obj=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
30819
11fdf7f2 30820 duk__enc_objarr_entry(js_ctx, &entry_top);
7c673cae
FG
30821
30822 idx_obj = entry_top - 1;
30823
30824 if (js_ctx->idx_proplist >= 0) {
30825 idx_keys = js_ctx->idx_proplist;
30826 } else {
30827 /* XXX: would be nice to enumerate an object at specified index */
30828 duk_dup(ctx, idx_obj);
30829 (void) duk_hobject_get_enumerated_keys(ctx, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/); /* [ ... target ] -> [ ... target keys ] */
30830 idx_keys = duk_require_normalize_index(ctx, -1);
30831 /* leave stack unbalanced on purpose */
30832 }
30833
30834 DUK_DDD(DUK_DDDPRINT("idx_keys=%ld, h_keys=%!T",
30835 (long) idx_keys, (duk_tval *) duk_get_tval(ctx, idx_keys)));
30836
30837 /* Steps 8-10 have been merged to avoid a "partial" variable. */
30838
30839 DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY);
30840
30841 /* XXX: keys is an internal object with all keys to be processed
30842 * in its (gapless) array part. Because nobody can touch the keys
30843 * object, we could iterate its array part directly (keeping in mind
30844 * that it can be reallocated).
30845 */
30846
30847 arr_len = (duk_uarridx_t) duk_get_length(ctx, idx_keys);
11fdf7f2 30848 emitted = 0;
7c673cae
FG
30849 for (i = 0; i < arr_len; i++) {
30850 duk_get_prop_index(ctx, idx_keys, i); /* -> [ ... key ] */
30851
30852 DUK_DDD(DUK_DDDPRINT("object property loop: holder=%!T, key=%!T",
30853 (duk_tval *) duk_get_tval(ctx, idx_obj),
30854 (duk_tval *) duk_get_tval(ctx, -1)));
30855
11fdf7f2 30856 h_key = duk_get_hstring(ctx, -1);
7c673cae 30857 DUK_ASSERT(h_key != NULL);
7c673cae 30858
11fdf7f2
TL
30859 prev_size = DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw);
30860 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
30861 duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
30862 duk__enc_key_autoquote(js_ctx, h_key);
7c673cae
FG
30863 DUK__EMIT_2(js_ctx, DUK_ASC_COLON, DUK_ASC_SPACE);
30864 } else {
11fdf7f2 30865 duk__enc_key_autoquote(js_ctx, h_key);
7c673cae
FG
30866 DUK__EMIT_1(js_ctx, DUK_ASC_COLON);
30867 }
30868
11fdf7f2 30869 /* [ ... key ] */
7c673cae 30870
11fdf7f2
TL
30871 if (DUK_UNLIKELY(duk__enc_value(js_ctx, idx_obj) == 0)) {
30872 /* Value would yield 'undefined', so skip key altogether.
30873 * Side effects have already happened.
30874 */
30875 DUK_BW_SET_SIZE(js_ctx->thr, &js_ctx->bw, prev_size);
30876 } else {
30877 DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
30878 emitted = 1;
30879 }
30880
30881 /* [ ... ] */
7c673cae
FG
30882 }
30883
11fdf7f2
TL
30884 if (emitted) {
30885 DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA);
30886 DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
30887 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
30888 DUK_ASSERT(js_ctx->recursion_depth >= 1);
30889 duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1);
7c673cae
FG
30890 }
30891 }
30892 DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY);
30893
11fdf7f2 30894 duk__enc_objarr_exit(js_ctx, &entry_top);
7c673cae
FG
30895
30896 DUK_ASSERT_TOP(ctx, entry_top);
30897}
30898
30899/* The JA(value) operation: encode array.
30900 *
30901 * Stack policy: [ array ] -> [ array ].
30902 */
30903DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) {
30904 duk_context *ctx = (duk_context *) js_ctx->thr;
7c673cae
FG
30905 duk_idx_t entry_top;
30906 duk_idx_t idx_arr;
11fdf7f2 30907 duk_bool_t emitted;
7c673cae
FG
30908 duk_uarridx_t i, arr_len;
30909
30910 DUK_DDD(DUK_DDDPRINT("duk__enc_array: array=%!T",
30911 (duk_tval *) duk_get_tval(ctx, -1)));
30912
11fdf7f2 30913 duk__enc_objarr_entry(js_ctx, &entry_top);
7c673cae
FG
30914
30915 idx_arr = entry_top - 1;
30916
30917 /* Steps 8-10 have been merged to avoid a "partial" variable. */
30918
30919 DUK__EMIT_1(js_ctx, DUK_ASC_LBRACKET);
30920
30921 arr_len = (duk_uarridx_t) duk_get_length(ctx, idx_arr);
11fdf7f2 30922 emitted = 0;
7c673cae 30923 for (i = 0; i < arr_len; i++) {
11fdf7f2
TL
30924 DUK_DDD(DUK_DDDPRINT("array entry loop: array=%!T, index=%ld, arr_len=%ld",
30925 (duk_tval *) duk_get_tval(ctx, idx_arr),
30926 (long) i, (long) arr_len));
7c673cae 30927
11fdf7f2
TL
30928 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
30929 DUK_ASSERT(js_ctx->recursion_depth >= 1);
30930 duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
7c673cae
FG
30931 }
30932
30933 /* XXX: duk_push_uint_string() */
30934 duk_push_uint(ctx, (duk_uint_t) i);
30935 duk_to_string(ctx, -1); /* -> [ ... key ] */
7c673cae 30936
11fdf7f2
TL
30937 /* [ ... key ] */
30938
30939 if (DUK_UNLIKELY(duk__enc_value(js_ctx, idx_arr) == 0)) {
30940 /* Value would normally be omitted, replace with 'null'. */
7c673cae
FG
30941 DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
30942 } else {
11fdf7f2 30943 ;
7c673cae 30944 }
11fdf7f2
TL
30945
30946 /* [ ... ] */
30947
30948 DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
30949 emitted = 1;
7c673cae
FG
30950 }
30951
11fdf7f2
TL
30952 if (emitted) {
30953 DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA);
30954 DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
30955 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
30956 DUK_ASSERT(js_ctx->recursion_depth >= 1);
30957 duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1);
7c673cae
FG
30958 }
30959 }
30960 DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET);
30961
11fdf7f2 30962 duk__enc_objarr_exit(js_ctx, &entry_top);
7c673cae
FG
30963
30964 DUK_ASSERT_TOP(ctx, entry_top);
30965}
30966
11fdf7f2 30967/* The Str(key, holder) operation.
7c673cae 30968 *
11fdf7f2 30969 * Stack policy: [ ... key ] -> [ ... ]
7c673cae 30970 */
11fdf7f2 30971DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_holder) {
7c673cae
FG
30972 duk_context *ctx = (duk_context *) js_ctx->thr;
30973 duk_hthread *thr = (duk_hthread *) ctx;
11fdf7f2 30974 duk_hobject *h_tmp;
7c673cae 30975 duk_tval *tv;
11fdf7f2
TL
30976 duk_tval *tv_holder;
30977 duk_tval *tv_key;
7c673cae
FG
30978 duk_small_int_t c;
30979
11fdf7f2 30980 DUK_DDD(DUK_DDDPRINT("duk__enc_value: idx_holder=%ld, holder=%!T, key=%!T",
7c673cae
FG
30981 (long) idx_holder, (duk_tval *) duk_get_tval(ctx, idx_holder),
30982 (duk_tval *) duk_get_tval(ctx, -1)));
30983
30984 DUK_UNREF(thr);
30985
11fdf7f2
TL
30986 tv_holder = DUK_GET_TVAL_POSIDX(ctx, idx_holder);
30987 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_holder));
30988 tv_key = DUK_GET_TVAL_NEGIDX(ctx, -1);
30989 DUK_ASSERT(DUK_TVAL_IS_STRING(tv_key));
30990 (void) duk_hobject_getprop(thr, tv_holder, tv_key);
30991
30992 /* -> [ ... key val ] */
7c673cae
FG
30993
30994 DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
30995
11fdf7f2
TL
30996 h_tmp = duk_get_hobject_or_lfunc_coerce(ctx, -1);
30997 if (h_tmp != NULL) {
7c673cae 30998 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_TO_JSON);
11fdf7f2 30999 h_tmp = duk_get_hobject_or_lfunc_coerce(ctx, -1); /* toJSON() can also be a lightfunc */
7c673cae 31000
11fdf7f2 31001 if (h_tmp != NULL && DUK_HOBJECT_IS_CALLABLE(h_tmp)) {
7c673cae 31002 DUK_DDD(DUK_DDDPRINT("value is object, has callable toJSON() -> call it"));
11fdf7f2 31003 /* XXX: duk_dup_unvalidated(ctx, -2) etc. */
7c673cae
FG
31004 duk_dup(ctx, -2); /* -> [ ... key val toJSON val ] */
31005 duk_dup(ctx, -4); /* -> [ ... key val toJSON val key ] */
31006 duk_call_method(ctx, 1); /* -> [ ... key val val' ] */
31007 duk_remove(ctx, -2); /* -> [ ... key val' ] */
31008 } else {
11fdf7f2 31009 duk_pop(ctx); /* -> [ ... key val ] */
7c673cae
FG
31010 }
31011 }
31012
31013 /* [ ... key val ] */
31014
31015 DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
31016
31017 if (js_ctx->h_replacer) {
11fdf7f2 31018 /* XXX: Here a "slice copy" would be useful. */
7c673cae
FG
31019 DUK_DDD(DUK_DDDPRINT("replacer is set, call replacer"));
31020 duk_push_hobject(ctx, js_ctx->h_replacer); /* -> [ ... key val replacer ] */
31021 duk_dup(ctx, idx_holder); /* -> [ ... key val replacer holder ] */
31022 duk_dup(ctx, -4); /* -> [ ... key val replacer holder key ] */
31023 duk_dup(ctx, -4); /* -> [ ... key val replacer holder key val ] */
31024 duk_call_method(ctx, 2); /* -> [ ... key val val' ] */
31025 duk_remove(ctx, -2); /* -> [ ... key val' ] */
31026 }
31027
31028 /* [ ... key val ] */
31029
31030 DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
31031
11fdf7f2 31032 tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
7c673cae 31033 if (DUK_TVAL_IS_OBJECT(tv)) {
11fdf7f2
TL
31034 duk_hobject *h;
31035
7c673cae
FG
31036 h = DUK_TVAL_GET_OBJECT(tv);
31037 DUK_ASSERT(h != NULL);
31038
31039 if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
11fdf7f2 31040#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
7c673cae
FG
31041 duk_hbufferobject *h_bufobj;
31042 h_bufobj = (duk_hbufferobject *) h;
31043 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
7c673cae 31044
11fdf7f2
TL
31045 /* Conceptually we'd extract the plain underlying buffer
31046 * or its slice and then do a type mask check below to
31047 * see if we should reject it. Do the mask check here
31048 * instead to avoid making a copy of the buffer slice.
31049 */
31050
31051 if (js_ctx->mask_for_undefined & DUK_TYPE_MASK_BUFFER) {
31052 DUK_DDD(DUK_DDDPRINT("-> bufferobject (-> plain buffer) will result in undefined (type mask check)"));
31053 goto pop2_undef;
7c673cae 31054 }
11fdf7f2
TL
31055 DUK_DDD(DUK_DDDPRINT("-> bufferobject won't result in undefined, encode directly"));
31056 duk__enc_bufferobject(js_ctx, h_bufobj);
31057 goto pop2_emitted;
31058#else
31059 DUK_DDD(DUK_DDDPRINT("no JX/JC support, bufferobject/buffer will always result in undefined"));
31060 goto pop2_undef;
31061#endif
7c673cae
FG
31062 } else {
31063 c = (duk_small_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h);
31064 switch ((int) c) {
31065 case DUK_HOBJECT_CLASS_NUMBER: {
31066 DUK_DDD(DUK_DDDPRINT("value is a Number object -> coerce with ToNumber()"));
31067 duk_to_number(ctx, -1);
11fdf7f2
TL
31068 /* The coercion potentially invokes user .valueOf() and .toString()
31069 * but can't result in a function value because [[DefaultValue]] would
31070 * reject such a result: test-dev-json-stringify-coercion-1.js.
31071 */
31072 DUK_ASSERT(!duk_is_callable(ctx, -1));
7c673cae
FG
31073 break;
31074 }
31075 case DUK_HOBJECT_CLASS_STRING: {
31076 DUK_DDD(DUK_DDDPRINT("value is a String object -> coerce with ToString()"));
31077 duk_to_string(ctx, -1);
11fdf7f2
TL
31078 /* Same coercion behavior as for Number. */
31079 DUK_ASSERT(!duk_is_callable(ctx, -1));
7c673cae
FG
31080 break;
31081 }
31082#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31083 case DUK_HOBJECT_CLASS_POINTER:
31084#endif
31085 case DUK_HOBJECT_CLASS_BOOLEAN: {
31086 DUK_DDD(DUK_DDDPRINT("value is a Boolean/Buffer/Pointer object -> get internal value"));
31087 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
31088 duk_remove(ctx, -2);
31089 break;
31090 }
11fdf7f2
TL
31091 default: {
31092 /* Normal object which doesn't get automatically coerced to a
31093 * primitive value. Functions are checked for specially. The
31094 * primitive value coercions for Number, String, Pointer, and
31095 * Boolean can't result in functions so suffices to check here.
31096 */
31097 DUK_ASSERT(h != NULL);
31098 if (DUK_HOBJECT_IS_CALLABLE(h)) {
31099#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31100 if (js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM |
31101 DUK_JSON_FLAG_EXT_COMPATIBLE)) {
31102 /* We only get here when doing non-standard JSON encoding */
31103 DUK_DDD(DUK_DDDPRINT("-> function allowed, serialize to custom format"));
31104 DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible);
31105 DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function);
31106 goto pop2_emitted;
31107 } else {
31108 DUK_DDD(DUK_DDDPRINT("-> will result in undefined (function)"));
31109 goto pop2_undef;
31110 }
31111#else /* DUK_USE_JX || DUK_USE_JC */
31112 DUK_DDD(DUK_DDDPRINT("-> will result in undefined (function)"));
31113 goto pop2_undef;
31114#endif /* DUK_USE_JX || DUK_USE_JC */
31115 }
31116 }
7c673cae
FG
31117 } /* end switch */
31118 }
31119 }
31120
31121 /* [ ... key val ] */
31122
31123 DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
31124
31125 if (duk_check_type_mask(ctx, -1, js_ctx->mask_for_undefined)) {
31126 /* will result in undefined */
31127 DUK_DDD(DUK_DDDPRINT("-> will result in undefined (type mask check)"));
11fdf7f2 31128 goto pop2_undef;
7c673cae 31129 }
11fdf7f2 31130 tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
7c673cae
FG
31131
31132 switch (DUK_TVAL_GET_TAG(tv)) {
31133#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
11fdf7f2 31134 /* When JX/JC not in use, the type mask above will avoid this case if needed. */
7c673cae
FG
31135 case DUK_TAG_UNDEFINED: {
31136 DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined);
31137 break;
31138 }
31139#endif
31140 case DUK_TAG_NULL: {
31141 DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
31142 break;
31143 }
31144 case DUK_TAG_BOOLEAN: {
31145 DUK__EMIT_STRIDX(js_ctx, DUK_TVAL_GET_BOOLEAN(tv) ?
31146 DUK_STRIDX_TRUE : DUK_STRIDX_FALSE);
31147 break;
31148 }
31149#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
11fdf7f2 31150 /* When JX/JC not in use, the type mask above will avoid this case if needed. */
7c673cae 31151 case DUK_TAG_POINTER: {
11fdf7f2 31152 duk__enc_pointer(js_ctx, DUK_TVAL_GET_POINTER(tv));
7c673cae
FG
31153 break;
31154 }
31155#endif /* DUK_USE_JX || DUK_USE_JC */
31156 case DUK_TAG_STRING: {
31157 duk_hstring *h = DUK_TVAL_GET_STRING(tv);
31158 DUK_ASSERT(h != NULL);
31159
31160 duk__enc_quote_string(js_ctx, h);
31161 break;
31162 }
31163 case DUK_TAG_OBJECT: {
31164 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
31165 DUK_ASSERT(h != NULL);
31166
11fdf7f2
TL
31167 /* Function values are handled completely above (including
31168 * coercion results):
31169 */
31170 DUK_ASSERT(!DUK_HOBJECT_IS_CALLABLE(h));
31171
7c673cae
FG
31172 if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY) {
31173 duk__enc_array(js_ctx);
31174 } else {
31175 duk__enc_object(js_ctx);
31176 }
31177 break;
31178 }
31179#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
11fdf7f2 31180 /* When JX/JC not in use, the type mask above will avoid this case if needed. */
7c673cae 31181 case DUK_TAG_BUFFER: {
11fdf7f2 31182 duk__enc_buffer(js_ctx, DUK_TVAL_GET_BUFFER(tv));
7c673cae
FG
31183 break;
31184 }
31185#endif /* DUK_USE_JX || DUK_USE_JC */
31186 case DUK_TAG_LIGHTFUNC: {
31187#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31188 /* We only get here when doing non-standard JSON encoding */
31189 DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible);
31190 DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function);
31191#else
31192 /* Standard JSON omits functions */
31193 DUK_UNREACHABLE();
31194#endif
31195 break;
31196 }
31197#if defined(DUK_USE_FASTINT)
31198 case DUK_TAG_FASTINT:
31199 /* Number serialization has a significant impact relative to
31200 * other fast path code, so careful fast path for fastints.
31201 */
31202 duk__enc_fastint_tval(js_ctx, tv);
31203 break;
31204#endif
31205 default: {
31206 /* number */
11fdf7f2
TL
31207 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
31208 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
7c673cae
FG
31209 /* XXX: A fast path for usual integers would be useful when
31210 * fastint support is not enabled.
31211 */
31212 duk__enc_double(js_ctx);
31213 break;
31214 }
31215 }
31216
11fdf7f2
TL
31217 pop2_emitted:
31218 duk_pop_2(ctx); /* [ ... key val ] -> [ ... ] */
31219 return 1; /* emitted */
7c673cae 31220
11fdf7f2
TL
31221 pop2_undef:
31222 duk_pop_2(ctx); /* [ ... key val ] -> [ ... ] */
31223 return 0; /* not emitted */
7c673cae
FG
31224}
31225
31226/* E5 Section 15.12.3, main algorithm, step 4.b.ii steps 1-4. */
31227DUK_LOCAL duk_bool_t duk__enc_allow_into_proplist(duk_tval *tv) {
31228 duk_hobject *h;
31229 duk_small_int_t c;
31230
31231 DUK_ASSERT(tv != NULL);
31232 if (DUK_TVAL_IS_STRING(tv) || DUK_TVAL_IS_NUMBER(tv)) {
31233 return 1;
31234 } else if (DUK_TVAL_IS_OBJECT(tv)) {
31235 h = DUK_TVAL_GET_OBJECT(tv);
31236 DUK_ASSERT(h != NULL);
31237 c = (duk_small_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h);
31238 if (c == DUK_HOBJECT_CLASS_STRING || c == DUK_HOBJECT_CLASS_NUMBER) {
31239 return 1;
31240 }
31241 }
31242
31243 return 0;
31244}
31245
31246/*
31247 * JSON.stringify() fast path
11fdf7f2
TL
31248 *
31249 * Otherwise supports full JSON, JX, and JC features, but bails out on any
31250 * possible side effect which might change the value being serialized. The
31251 * fast path can take advantage of the fact that the value being serialized
31252 * is unchanged so that we can walk directly through property tables etc.
7c673cae
FG
31253 */
31254
31255#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
31256DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, duk_tval *tv) {
31257 duk_uint_fast32_t i, n;
31258
31259 DUK_DDD(DUK_DDDPRINT("stringify fast: %!T", tv));
31260
31261 DUK_ASSERT(js_ctx != NULL);
31262 DUK_ASSERT(js_ctx->thr != NULL);
7c673cae 31263
11fdf7f2 31264#if 0 /* disabled for now */
7c673cae 31265 restart_match:
11fdf7f2
TL
31266#endif
31267
7c673cae
FG
31268 DUK_ASSERT(tv != NULL);
31269
31270 switch (DUK_TVAL_GET_TAG(tv)) {
31271 case DUK_TAG_UNDEFINED: {
11fdf7f2
TL
31272#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31273 if (js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible) {
31274 DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined);
31275 break;
31276 } else {
31277 goto emit_undefined;
31278 }
31279#else
7c673cae 31280 goto emit_undefined;
11fdf7f2 31281#endif
7c673cae
FG
31282 }
31283 case DUK_TAG_NULL: {
31284 DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
31285 break;
31286 }
31287 case DUK_TAG_BOOLEAN: {
31288 DUK__EMIT_STRIDX(js_ctx, DUK_TVAL_GET_BOOLEAN(tv) ?
31289 DUK_STRIDX_TRUE : DUK_STRIDX_FALSE);
31290 break;
31291 }
31292 case DUK_TAG_STRING: {
31293 duk_hstring *h;
31294
31295 h = DUK_TVAL_GET_STRING(tv);
31296 DUK_ASSERT(h != NULL);
31297 duk__enc_quote_string(js_ctx, h);
31298 break;
31299 }
31300 case DUK_TAG_OBJECT: {
31301 duk_hobject *obj;
31302 duk_tval *tv_val;
31303 duk_bool_t emitted = 0;
11fdf7f2
TL
31304 duk_uint32_t c_bit, c_all, c_array, c_unbox, c_undef,
31305 c_func, c_bufobj, c_object;
7c673cae
FG
31306
31307 /* For objects JSON.stringify() only looks for own, enumerable
31308 * properties which is nice for the fast path here.
31309 *
31310 * For arrays JSON.stringify() uses [[Get]] so it will actually
31311 * inherit properties during serialization! This fast path
31312 * supports gappy arrays as long as there's no actual inherited
31313 * property (which might be a getter etc).
31314 *
31315 * Since recursion only happens for objects, we can have both
31316 * recursion and loop checks here. We use a simple, depth-limited
31317 * loop check in the fast path because the object-based tracking
31318 * is very slow (when tested, it accounted for 50% of fast path
31319 * execution time for input data with a lot of small objects!).
31320 */
31321
11fdf7f2
TL
31322 /* XXX: for real world code, could just ignore array inheritance
31323 * and only look at array own properties.
31324 */
7c673cae
FG
31325
31326 /* We rely on a few object flag / class number relationships here,
31327 * assert for them.
31328 */
11fdf7f2
TL
31329
31330 obj = DUK_TVAL_GET_OBJECT(tv);
31331 DUK_ASSERT(obj != NULL);
7c673cae
FG
31332 DUK_ASSERT_HOBJECT_VALID(obj);
31333
31334 /* Once recursion depth is increased, exit path must decrease
31335 * it (though it's OK to abort the fast path).
31336 */
31337
31338 DUK_ASSERT(js_ctx->recursion_depth >= 0);
31339 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
31340 if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
31341 DUK_DD(DUK_DDPRINT("fast path recursion limit"));
11fdf7f2 31342 DUK_ERROR_RANGE(js_ctx->thr, DUK_STR_JSONDEC_RECLIMIT);
7c673cae
FG
31343 }
31344
31345 for (i = 0, n = (duk_uint_fast32_t) js_ctx->recursion_depth; i < n; i++) {
11fdf7f2 31346 if (DUK_UNLIKELY(js_ctx->visiting[i] == obj)) {
7c673cae 31347 DUK_DD(DUK_DDPRINT("fast path loop detect"));
11fdf7f2 31348 DUK_ERROR_TYPE(js_ctx->thr, DUK_STR_CYCLIC_INPUT);
7c673cae
FG
31349 }
31350 }
31351
31352 /* Guaranteed by recursion_limit setup so we don't have to
31353 * check twice.
31354 */
31355 DUK_ASSERT(js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY);
31356 js_ctx->visiting[js_ctx->recursion_depth] = obj;
31357 js_ctx->recursion_depth++;
31358
31359 /* If object has a .toJSON() property, we can't be certain
31360 * that it wouldn't mutate any value arbitrarily, so bail
31361 * out of the fast path.
31362 *
31363 * If an object is a Proxy we also can't avoid side effects
31364 * so abandon.
31365 */
11fdf7f2
TL
31366 /* XXX: non-callable .toJSON() doesn't need to cause an abort
31367 * but does at the moment, probably not worth fixing.
31368 */
7c673cae
FG
31369 if (duk_hobject_hasprop_raw(js_ctx->thr, obj, DUK_HTHREAD_STRING_TO_JSON(js_ctx->thr)) ||
31370 DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj)) {
31371 DUK_DD(DUK_DDPRINT("object has a .toJSON property or object is a Proxy, abort fast path"));
31372 goto abort_fastpath;
31373 }
31374
31375 /* We could use a switch-case for the class number but it turns out
31376 * a small if-else ladder on class masks is better. The if-ladder
31377 * should be in order of relevancy.
31378 */
31379
11fdf7f2
TL
31380 /* XXX: move masks to js_ctx? they don't change during one
31381 * fast path invocation.
31382 */
7c673cae 31383 DUK_ASSERT(DUK_HOBJECT_CLASS_MAX <= 31);
11fdf7f2
TL
31384#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31385 if (js_ctx->flag_ext_custom_or_compatible) {
31386 c_all = DUK_HOBJECT_CMASK_ALL;
31387 c_array = DUK_HOBJECT_CMASK_ARRAY;
31388 c_unbox = DUK_HOBJECT_CMASK_NUMBER |
31389 DUK_HOBJECT_CMASK_STRING |
31390 DUK_HOBJECT_CMASK_BOOLEAN |
31391 DUK_HOBJECT_CMASK_POINTER;
31392 c_func = DUK_HOBJECT_CMASK_FUNCTION;
31393 c_bufobj = DUK_HOBJECT_CMASK_ALL_BUFFEROBJECTS;
31394 c_undef = 0;
31395 c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef);
31396 }
31397 else
31398#endif
31399 {
31400 c_all = DUK_HOBJECT_CMASK_ALL;
31401 c_array = DUK_HOBJECT_CMASK_ARRAY;
31402 c_unbox = DUK_HOBJECT_CMASK_NUMBER |
31403 DUK_HOBJECT_CMASK_STRING |
31404 DUK_HOBJECT_CMASK_BOOLEAN;
31405 c_func = 0;
31406 c_bufobj = 0;
31407 c_undef = DUK_HOBJECT_CMASK_FUNCTION |
31408 DUK_HOBJECT_CMASK_POINTER |
31409 DUK_HOBJECT_CMASK_ALL_BUFFEROBJECTS;
31410 c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef);
31411 }
7c673cae
FG
31412
31413 c_bit = DUK_HOBJECT_GET_CLASS_MASK(obj);
31414 if (c_bit & c_object) {
31415 /* All other object types. */
31416 DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY);
31417
31418 /* A non-Array object should not have an array part in practice.
31419 * But since it is supported internally (and perhaps used at some
31420 * point), check and abandon if that's the case.
31421 */
31422 if (DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
31423 DUK_DD(DUK_DDPRINT("non-Array object has array part, abort fast path"));
31424 goto abort_fastpath;
31425 }
31426
31427 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(obj); i++) {
31428 duk_hstring *k;
31429 duk_size_t prev_size;
31430
31431 k = DUK_HOBJECT_E_GET_KEY(js_ctx->thr->heap, obj, i);
31432 if (!k) {
31433 continue;
31434 }
31435 if (!DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(js_ctx->thr->heap, obj, i)) {
31436 continue;
31437 }
31438 if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(js_ctx->thr->heap, obj, i)) {
31439 /* Getter might have arbitrary side effects,
31440 * so bail out.
31441 */
31442 DUK_DD(DUK_DDPRINT("property is an accessor, abort fast path"));
31443 goto abort_fastpath;
31444 }
31445 if (DUK_HSTRING_HAS_INTERNAL(k)) {
31446 continue;
31447 }
31448
31449 tv_val = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(js_ctx->thr->heap, obj, i);
31450
31451 prev_size = DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw);
11fdf7f2
TL
31452 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
31453 duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
31454 duk__enc_key_autoquote(js_ctx, k);
31455 DUK__EMIT_2(js_ctx, DUK_ASC_COLON, DUK_ASC_SPACE);
31456 } else {
31457 duk__enc_key_autoquote(js_ctx, k);
31458 DUK__EMIT_1(js_ctx, DUK_ASC_COLON);
31459 }
31460
7c673cae
FG
31461 if (duk__json_stringify_fast_value(js_ctx, tv_val) == 0) {
31462 DUK_DD(DUK_DDPRINT("prop value not supported, rewind key and colon"));
31463 DUK_BW_SET_SIZE(js_ctx->thr, &js_ctx->bw, prev_size);
31464 } else {
31465 DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
31466 emitted = 1;
31467 }
31468 }
31469
31470 /* If any non-Array value had enumerable virtual own
31471 * properties, they should be serialized here. Standard
31472 * types don't.
31473 */
31474
31475 if (emitted) {
11fdf7f2 31476 DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA);
7c673cae 31477 DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
11fdf7f2
TL
31478 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
31479 DUK_ASSERT(js_ctx->recursion_depth >= 1);
31480 duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1);
31481 }
7c673cae
FG
31482 }
31483 DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY);
31484 } else if (c_bit & c_array) {
31485 duk_uint_fast32_t arr_len;
31486 duk_uint_fast32_t asize;
31487
31488 DUK__EMIT_1(js_ctx, DUK_ASC_LBRACKET);
31489
31490 /* Assume arrays are dense in the fast path. */
31491 if (!DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
31492 DUK_DD(DUK_DDPRINT("Array object is sparse, abort fast path"));
31493 goto abort_fastpath;
31494 }
31495
31496 arr_len = (duk_uint_fast32_t) duk_hobject_get_length(js_ctx->thr, obj);
31497 asize = (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(obj);
31498 if (arr_len > asize) {
31499 /* Array length is larger than 'asize'. This shouldn't
31500 * happen in practice. Bail out just in case.
31501 */
31502 DUK_DD(DUK_DDPRINT("arr_len > asize, abort fast path"));
31503 goto abort_fastpath;
31504 }
31505 /* Array part may be larger than 'length'; if so, iterate
31506 * only up to array 'length'.
31507 */
31508 for (i = 0; i < arr_len; i++) {
31509 DUK_ASSERT(i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(obj));
31510
31511 tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(js_ctx->thr->heap, obj, i);
31512
11fdf7f2
TL
31513 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
31514 duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
31515 }
31516
31517 if (DUK_UNLIKELY(DUK_TVAL_IS_UNUSED(tv_val))) {
7c673cae
FG
31518 /* Gap in array; check for inherited property,
31519 * bail out if one exists. This should be enough
31520 * to support gappy arrays for all practical code.
31521 */
31522 duk_hstring *h_tmp;
31523 duk_bool_t has_inherited;
31524
31525 /* XXX: refactor into an internal helper, pretty awkward */
31526 duk_push_uint((duk_context *) js_ctx->thr, (duk_uint_t) i);
31527 h_tmp = duk_to_hstring((duk_context *) js_ctx->thr, -1);
31528 DUK_ASSERT(h_tmp != NULL);
31529 has_inherited = duk_hobject_hasprop_raw(js_ctx->thr, obj, h_tmp);
31530 duk_pop((duk_context *) js_ctx->thr);
31531
31532 if (has_inherited) {
31533 DUK_D(DUK_DPRINT("gap in array, conflicting inherited property, abort fast path"));
31534 goto abort_fastpath;
31535 }
31536
31537 /* Ordinary gap, undefined encodes to 'null' in
31538 * standard JSON (and no JX/JC support here now).
31539 */
31540 DUK_D(DUK_DPRINT("gap in array, no conflicting inherited property, remain on fast path"));
11fdf7f2
TL
31541#if defined(DUK_USE_JX)
31542 DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined);
31543#else
7c673cae 31544 DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
11fdf7f2 31545#endif
7c673cae
FG
31546 } else {
31547 if (duk__json_stringify_fast_value(js_ctx, tv_val) == 0) {
31548 DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
31549 }
31550 }
11fdf7f2 31551
7c673cae
FG
31552 DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
31553 emitted = 1;
31554 }
31555
31556 if (emitted) {
11fdf7f2 31557 DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA);
7c673cae 31558 DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
11fdf7f2
TL
31559 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
31560 DUK_ASSERT(js_ctx->recursion_depth >= 1);
31561 duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1);
31562 }
7c673cae
FG
31563 }
31564 DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET);
31565 } else if (c_bit & c_unbox) {
11fdf7f2 31566 /* Certain boxed types are required to go through
7c673cae
FG
31567 * automatic unboxing. Rely on internal value being
31568 * sane (to avoid infinite recursion).
31569 */
11fdf7f2
TL
31570#if 1
31571 /* The code below is incorrect if .toString() or .valueOf() have
31572 * have been overridden. The correct approach would be to look up
31573 * the method(s) and if they resolve to the built-in function we
31574 * can safely bypass it and look up the internal value directly.
31575 * Unimplemented for now, abort fast path for boxed values.
31576 */
31577 goto abort_fastpath;
31578#else /* disabled */
31579 /* Disabled until fixed, see above. */
7c673cae
FG
31580 duk_tval *tv_internal;
31581
31582 DUK_DD(DUK_DDPRINT("auto unboxing in fast path"));
31583
31584 tv_internal = duk_hobject_get_internal_value_tval_ptr(js_ctx->thr->heap, obj);
31585 DUK_ASSERT(tv_internal != NULL);
31586 DUK_ASSERT(DUK_TVAL_IS_STRING(tv_internal) ||
31587 DUK_TVAL_IS_NUMBER(tv_internal) ||
11fdf7f2
TL
31588 DUK_TVAL_IS_BOOLEAN(tv_internal) ||
31589 DUK_TVAL_IS_POINTER(tv_internal));
7c673cae 31590
7c673cae 31591 tv = tv_internal;
11fdf7f2
TL
31592 DUK_ASSERT(js_ctx->recursion_depth > 0);
31593 js_ctx->recursion_depth--; /* required to keep recursion depth correct */
7c673cae 31594 goto restart_match;
11fdf7f2
TL
31595#endif /* disabled */
31596#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31597 } else if (c_bit & c_func) {
31598 DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function);
31599 } else if (c_bit & c_bufobj) {
31600 duk__enc_bufferobject(js_ctx, (duk_hbufferobject *) obj);
31601#endif
7c673cae
FG
31602 } else {
31603 DUK_ASSERT((c_bit & c_undef) != 0);
31604
7c673cae
FG
31605 /* Must decrease recursion depth before returning. */
31606 DUK_ASSERT(js_ctx->recursion_depth > 0);
31607 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
31608 js_ctx->recursion_depth--;
31609 goto emit_undefined;
31610 }
31611
31612 DUK_ASSERT(js_ctx->recursion_depth > 0);
31613 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
31614 js_ctx->recursion_depth--;
31615 break;
31616 }
31617 case DUK_TAG_BUFFER: {
11fdf7f2
TL
31618#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31619 if (js_ctx->flag_ext_custom_or_compatible) {
31620 duk__enc_buffer(js_ctx, DUK_TVAL_GET_BUFFER(tv));
31621 break;
31622 } else {
31623 goto emit_undefined;
31624 }
31625#else
7c673cae 31626 goto emit_undefined;
11fdf7f2 31627#endif
7c673cae
FG
31628 }
31629 case DUK_TAG_POINTER: {
11fdf7f2
TL
31630#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31631 if (js_ctx->flag_ext_custom_or_compatible) {
31632 duk__enc_pointer(js_ctx, DUK_TVAL_GET_POINTER(tv));
31633 break;
31634 } else {
31635 goto emit_undefined;
31636 }
31637#else
7c673cae 31638 goto emit_undefined;
11fdf7f2 31639#endif
7c673cae
FG
31640 }
31641 case DUK_TAG_LIGHTFUNC: {
31642 /* A lightfunc might also inherit a .toJSON() so just bail out. */
11fdf7f2
TL
31643 /* XXX: Could just lookup .toJSON() and continue in fast path,
31644 * as it would almost never be defined.
31645 */
7c673cae
FG
31646 DUK_DD(DUK_DDPRINT("value is a lightfunc, abort fast path"));
31647 goto abort_fastpath;
31648 }
31649#if defined(DUK_USE_FASTINT)
31650 case DUK_TAG_FASTINT: {
31651 /* Number serialization has a significant impact relative to
31652 * other fast path code, so careful fast path for fastints.
31653 */
31654 duk__enc_fastint_tval(js_ctx, tv);
31655 break;
31656 }
31657#endif
31658 default: {
31659 /* XXX: A fast path for usual integers would be useful when
31660 * fastint support is not enabled.
31661 */
11fdf7f2
TL
31662 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
31663 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
31664
7c673cae
FG
31665 /* XXX: Stack discipline is annoying, could be changed in numconv. */
31666 duk_push_tval((duk_context *) js_ctx->thr, tv);
31667 duk__enc_double(js_ctx);
31668 duk_pop((duk_context *) js_ctx->thr);
31669
31670#if 0
31671 /* Could also rely on native sprintf(), but it will handle
31672 * values like NaN, Infinity, -0, exponent notation etc in
31673 * a JSON-incompatible way.
31674 */
31675 duk_double_t d;
31676 char buf[64];
31677
31678 DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
31679 d = DUK_TVAL_GET_DOUBLE(tv);
31680 DUK_SPRINTF(buf, "%lg", d);
31681 DUK__EMIT_CSTR(js_ctx, buf);
31682#endif
31683 }
31684 }
31685 return 1; /* not undefined */
31686
31687 emit_undefined:
31688 return 0; /* value was undefined/unsupported */
31689
31690 abort_fastpath:
31691 /* Error message doesn't matter: the error is ignored anyway. */
31692 DUK_DD(DUK_DDPRINT("aborting fast path"));
11fdf7f2 31693 DUK_ERROR_INTERNAL_DEFMSG(js_ctx->thr);
7c673cae
FG
31694 return 0; /* unreachable */
31695}
31696
31697DUK_LOCAL duk_ret_t duk__json_stringify_fast(duk_context *ctx) {
31698 duk_json_enc_ctx *js_ctx;
11fdf7f2 31699 duk_tval *tv;
7c673cae
FG
31700
31701 DUK_ASSERT(ctx != NULL);
11fdf7f2
TL
31702 tv = DUK_GET_TVAL_NEGIDX(ctx, -2);
31703 DUK_ASSERT(DUK_TVAL_IS_POINTER(tv));
31704 js_ctx = (duk_json_enc_ctx *) DUK_TVAL_GET_POINTER(tv);
7c673cae
FG
31705 DUK_ASSERT(js_ctx != NULL);
31706
11fdf7f2
TL
31707 tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
31708 if (duk__json_stringify_fast_value(js_ctx, tv) == 0) {
7c673cae
FG
31709 DUK_DD(DUK_DDPRINT("top level value not supported, fail fast path"));
31710 return DUK_RET_ERROR; /* error message doesn't matter, ignored anyway */
31711 }
31712
31713 return 0;
31714}
31715#endif /* DUK_USE_JSON_STRINGIFY_FASTPATH */
31716
31717/*
31718 * Top level wrappers
31719 */
31720
31721DUK_INTERNAL
31722void duk_bi_json_parse_helper(duk_context *ctx,
31723 duk_idx_t idx_value,
31724 duk_idx_t idx_reviver,
31725 duk_small_uint_t flags) {
31726 duk_hthread *thr = (duk_hthread *) ctx;
31727 duk_json_dec_ctx js_ctx_alloc;
31728 duk_json_dec_ctx *js_ctx = &js_ctx_alloc;
31729 duk_hstring *h_text;
31730#ifdef DUK_USE_ASSERTIONS
31731 duk_idx_t entry_top = duk_get_top(ctx);
31732#endif
31733
31734 /* negative top-relative indices not allowed now */
31735 DUK_ASSERT(idx_value == DUK_INVALID_INDEX || idx_value >= 0);
31736 DUK_ASSERT(idx_reviver == DUK_INVALID_INDEX || idx_reviver >= 0);
31737
31738 DUK_DDD(DUK_DDDPRINT("JSON parse start: text=%!T, reviver=%!T, flags=0x%08lx, stack_top=%ld",
31739 (duk_tval *) duk_get_tval(ctx, idx_value),
31740 (duk_tval *) duk_get_tval(ctx, idx_reviver),
31741 (unsigned long) flags,
31742 (long) duk_get_top(ctx)));
31743
31744 DUK_MEMZERO(&js_ctx_alloc, sizeof(js_ctx_alloc));
31745 js_ctx->thr = thr;
31746#ifdef DUK_USE_EXPLICIT_NULL_INIT
31747 /* nothing now */
31748#endif
31749 js_ctx->recursion_limit = DUK_USE_JSON_DEC_RECLIMIT;
31750 DUK_ASSERT(js_ctx->recursion_depth == 0);
31751
31752 /* Flag handling currently assumes that flags are consistent. This is OK
31753 * because the call sites are now strictly controlled.
31754 */
31755
31756 js_ctx->flags = flags;
11fdf7f2 31757#if defined(DUK_USE_JX)
7c673cae
FG
31758 js_ctx->flag_ext_custom = flags & DUK_JSON_FLAG_EXT_CUSTOM;
31759#endif
11fdf7f2 31760#if defined(DUK_USE_JC)
7c673cae
FG
31761 js_ctx->flag_ext_compatible = flags & DUK_JSON_FLAG_EXT_COMPATIBLE;
31762#endif
11fdf7f2
TL
31763#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31764 js_ctx->flag_ext_custom_or_compatible = flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE);
31765#endif
7c673cae
FG
31766
31767 h_text = duk_to_hstring(ctx, idx_value); /* coerce in-place */
31768 DUK_ASSERT(h_text != NULL);
31769
31770 /* JSON parsing code is allowed to read [p_start,p_end]: p_end is
31771 * valid and points to the string NUL terminator (which is always
31772 * guaranteed for duk_hstrings.
31773 */
11fdf7f2 31774 js_ctx->p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text);
7c673cae 31775 js_ctx->p = js_ctx->p_start;
11fdf7f2 31776 js_ctx->p_end = ((const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text)) +
7c673cae
FG
31777 DUK_HSTRING_GET_BYTELEN(h_text);
31778 DUK_ASSERT(*(js_ctx->p_end) == 0x00);
31779
31780 duk__dec_value(js_ctx); /* -> [ ... value ] */
31781
31782 /* Trailing whitespace has been eaten by duk__dec_value(), so if
31783 * we're not at end of input here, it's a SyntaxError.
31784 */
31785
31786 if (js_ctx->p != js_ctx->p_end) {
31787 duk__dec_syntax_error(js_ctx);
31788 }
31789
31790 if (duk_is_callable(ctx, idx_reviver)) {
31791 DUK_DDD(DUK_DDDPRINT("applying reviver: %!T",
31792 (duk_tval *) duk_get_tval(ctx, idx_reviver)));
31793
31794 js_ctx->idx_reviver = idx_reviver;
31795
31796 duk_push_object(ctx);
31797 duk_dup(ctx, -2); /* -> [ ... val root val ] */
31798 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_EMPTY_STRING); /* default attrs ok */
31799 duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING); /* -> [ ... val root "" ] */
31800
31801 DUK_DDD(DUK_DDDPRINT("start reviver walk, root=%!T, name=%!T",
31802 (duk_tval *) duk_get_tval(ctx, -2),
31803 (duk_tval *) duk_get_tval(ctx, -1)));
31804
31805 duk__dec_reviver_walk(js_ctx); /* [ ... val root "" ] -> [ ... val val' ] */
31806 duk_remove(ctx, -2); /* -> [ ... val' ] */
31807 } else {
31808 DUK_DDD(DUK_DDDPRINT("reviver does not exist or is not callable: %!T",
31809 (duk_tval *) duk_get_tval(ctx, idx_reviver)));
31810 }
31811
31812 /* Final result is at stack top. */
31813
31814 DUK_DDD(DUK_DDDPRINT("JSON parse end: text=%!T, reviver=%!T, flags=0x%08lx, result=%!T, stack_top=%ld",
31815 (duk_tval *) duk_get_tval(ctx, idx_value),
31816 (duk_tval *) duk_get_tval(ctx, idx_reviver),
31817 (unsigned long) flags,
31818 (duk_tval *) duk_get_tval(ctx, -1),
31819 (long) duk_get_top(ctx)));
31820
31821 DUK_ASSERT(duk_get_top(ctx) == entry_top + 1);
31822}
31823
31824DUK_INTERNAL
31825void duk_bi_json_stringify_helper(duk_context *ctx,
31826 duk_idx_t idx_value,
31827 duk_idx_t idx_replacer,
31828 duk_idx_t idx_space,
31829 duk_small_uint_t flags) {
31830 duk_hthread *thr = (duk_hthread *) ctx;
31831 duk_json_enc_ctx js_ctx_alloc;
31832 duk_json_enc_ctx *js_ctx = &js_ctx_alloc;
31833 duk_hobject *h;
7c673cae
FG
31834 duk_idx_t idx_holder;
31835 duk_idx_t entry_top;
31836
31837 /* negative top-relative indices not allowed now */
31838 DUK_ASSERT(idx_value == DUK_INVALID_INDEX || idx_value >= 0);
31839 DUK_ASSERT(idx_replacer == DUK_INVALID_INDEX || idx_replacer >= 0);
31840 DUK_ASSERT(idx_space == DUK_INVALID_INDEX || idx_space >= 0);
31841
31842 DUK_DDD(DUK_DDDPRINT("JSON stringify start: value=%!T, replacer=%!T, space=%!T, flags=0x%08lx, stack_top=%ld",
31843 (duk_tval *) duk_get_tval(ctx, idx_value),
31844 (duk_tval *) duk_get_tval(ctx, idx_replacer),
31845 (duk_tval *) duk_get_tval(ctx, idx_space),
31846 (unsigned long) flags,
31847 (long) duk_get_top(ctx)));
31848
31849 entry_top = duk_get_top(ctx);
31850
31851 /*
31852 * Context init
31853 */
31854
31855 DUK_MEMZERO(&js_ctx_alloc, sizeof(js_ctx_alloc));
31856 js_ctx->thr = thr;
31857#ifdef DUK_USE_EXPLICIT_NULL_INIT
31858 js_ctx->h_replacer = NULL;
31859 js_ctx->h_gap = NULL;
7c673cae
FG
31860#endif
31861 js_ctx->idx_proplist = -1;
31862
31863 /* Flag handling currently assumes that flags are consistent. This is OK
31864 * because the call sites are now strictly controlled.
31865 */
31866
31867 js_ctx->flags = flags;
31868 js_ctx->flag_ascii_only = flags & DUK_JSON_FLAG_ASCII_ONLY;
31869 js_ctx->flag_avoid_key_quotes = flags & DUK_JSON_FLAG_AVOID_KEY_QUOTES;
31870#ifdef DUK_USE_JX
31871 js_ctx->flag_ext_custom = flags & DUK_JSON_FLAG_EXT_CUSTOM;
31872#endif
31873#ifdef DUK_USE_JC
31874 js_ctx->flag_ext_compatible = flags & DUK_JSON_FLAG_EXT_COMPATIBLE;
31875#endif
11fdf7f2
TL
31876#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31877 js_ctx->flag_ext_custom_or_compatible = flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE);
31878#endif
7c673cae
FG
31879
31880 /* The #ifdef clutter here handles the JX/JC enable/disable
31881 * combinations properly.
31882 */
31883#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
11fdf7f2 31884 js_ctx->stridx_custom_undefined = DUK_STRIDX_LC_NULL; /* standard JSON; array gaps */
7c673cae
FG
31885#if defined(DUK_USE_JX)
31886 if (flags & DUK_JSON_FLAG_EXT_CUSTOM) {
31887 js_ctx->stridx_custom_undefined = DUK_STRIDX_LC_UNDEFINED;
31888 js_ctx->stridx_custom_nan = DUK_STRIDX_NAN;
31889 js_ctx->stridx_custom_neginf = DUK_STRIDX_MINUS_INFINITY;
31890 js_ctx->stridx_custom_posinf = DUK_STRIDX_INFINITY;
31891 js_ctx->stridx_custom_function =
31892 (flags & DUK_JSON_FLAG_AVOID_KEY_QUOTES) ?
31893 DUK_STRIDX_JSON_EXT_FUNCTION2 :
31894 DUK_STRIDX_JSON_EXT_FUNCTION1;
31895 }
31896#endif /* DUK_USE_JX */
31897#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
31898 else
31899#endif /* DUK_USE_JX && DUK_USE_JC */
31900#if defined(DUK_USE_JC)
31901 if (js_ctx->flags & DUK_JSON_FLAG_EXT_COMPATIBLE) {
31902 js_ctx->stridx_custom_undefined = DUK_STRIDX_JSON_EXT_UNDEFINED;
31903 js_ctx->stridx_custom_nan = DUK_STRIDX_JSON_EXT_NAN;
31904 js_ctx->stridx_custom_neginf = DUK_STRIDX_JSON_EXT_NEGINF;
31905 js_ctx->stridx_custom_posinf = DUK_STRIDX_JSON_EXT_POSINF;
31906 js_ctx->stridx_custom_function = DUK_STRIDX_JSON_EXT_FUNCTION1;
31907 }
31908#endif /* DUK_USE_JC */
31909#endif /* DUK_USE_JX || DUK_USE_JC */
31910
31911#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31912 if (js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM |
31913 DUK_JSON_FLAG_EXT_COMPATIBLE)) {
31914 DUK_ASSERT(js_ctx->mask_for_undefined == 0); /* already zero */
31915 }
31916 else
31917#endif /* DUK_USE_JX || DUK_USE_JC */
31918 {
31919 js_ctx->mask_for_undefined = DUK_TYPE_MASK_UNDEFINED |
31920 DUK_TYPE_MASK_POINTER |
31921 DUK_TYPE_MASK_BUFFER |
31922 DUK_TYPE_MASK_LIGHTFUNC;
31923 }
31924
31925 DUK_BW_INIT_PUSHBUF(thr, &js_ctx->bw, DUK__JSON_STRINGIFY_BUFSIZE);
31926
31927 js_ctx->idx_loop = duk_push_object_internal(ctx);
31928 DUK_ASSERT(js_ctx->idx_loop >= 0);
31929
31930 /* [ ... buf loop ] */
31931
31932 /*
31933 * Process replacer/proplist (2nd argument to JSON.stringify)
31934 */
31935
31936 h = duk_get_hobject(ctx, idx_replacer);
31937 if (h != NULL) {
31938 if (DUK_HOBJECT_IS_CALLABLE(h)) {
31939 js_ctx->h_replacer = h;
31940 } else if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY) {
31941 /* Here the specification requires correct array index enumeration
31942 * which is a bit tricky for sparse arrays (it is handled by the
31943 * enum setup code). We now enumerate ancestors too, although the
31944 * specification is not very clear on whether that is required.
31945 */
31946
31947 duk_uarridx_t plist_idx = 0;
31948 duk_small_uint_t enum_flags;
31949
31950 js_ctx->idx_proplist = duk_push_array(ctx); /* XXX: array internal? */
31951
31952 enum_flags = DUK_ENUM_ARRAY_INDICES_ONLY |
31953 DUK_ENUM_SORT_ARRAY_INDICES; /* expensive flag */
31954 duk_enum(ctx, idx_replacer, enum_flags);
31955 while (duk_next(ctx, -1 /*enum_index*/, 1 /*get_value*/)) {
31956 /* [ ... proplist enum_obj key val ] */
31957 if (duk__enc_allow_into_proplist(duk_get_tval(ctx, -1))) {
31958 /* XXX: duplicates should be eliminated here */
31959 DUK_DDD(DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> accept",
31960 (duk_tval *) duk_get_tval(ctx, -2),
31961 (duk_tval *) duk_get_tval(ctx, -1)));
31962 duk_to_string(ctx, -1); /* extra coercion of strings is OK */
31963 duk_put_prop_index(ctx, -4, plist_idx); /* -> [ ... proplist enum_obj key ] */
31964 plist_idx++;
31965 duk_pop(ctx);
31966 } else {
31967 DUK_DDD(DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> reject",
31968 (duk_tval *) duk_get_tval(ctx, -2),
31969 (duk_tval *) duk_get_tval(ctx, -1)));
31970 duk_pop_2(ctx);
31971 }
31972 }
31973 duk_pop(ctx); /* pop enum */
31974
31975 /* [ ... proplist ] */
31976 }
31977 }
31978
31979 /* [ ... buf loop (proplist) ] */
31980
31981 /*
31982 * Process space (3rd argument to JSON.stringify)
31983 */
31984
31985 h = duk_get_hobject(ctx, idx_space);
31986 if (h != NULL) {
31987 int c = DUK_HOBJECT_GET_CLASS_NUMBER(h);
31988 if (c == DUK_HOBJECT_CLASS_NUMBER) {
31989 duk_to_number(ctx, idx_space);
31990 } else if (c == DUK_HOBJECT_CLASS_STRING) {
31991 duk_to_string(ctx, idx_space);
31992 }
31993 }
31994
31995 if (duk_is_number(ctx, idx_space)) {
31996 duk_small_int_t nspace;
31997 /* spaces[] must be static to allow initializer with old compilers like BCC */
31998 static const char spaces[10] = {
31999 DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE,
32000 DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE,
32001 DUK_ASC_SPACE, DUK_ASC_SPACE
32002 }; /* XXX: helper */
32003
32004 /* ToInteger() coercion; NaN -> 0, infinities are clamped to 0 and 10 */
32005 nspace = (duk_small_int_t) duk_to_int_clamped(ctx, idx_space, 0 /*minval*/, 10 /*maxval*/);
32006 DUK_ASSERT(nspace >= 0 && nspace <= 10);
32007
32008 duk_push_lstring(ctx, spaces, (duk_size_t) nspace);
32009 js_ctx->h_gap = duk_get_hstring(ctx, -1);
32010 DUK_ASSERT(js_ctx->h_gap != NULL);
32011 } else if (duk_is_string(ctx, idx_space)) {
32012 /* XXX: substring in-place at idx_place? */
32013 duk_dup(ctx, idx_space);
32014 duk_substring(ctx, -1, 0, 10); /* clamp to 10 chars */
32015 js_ctx->h_gap = duk_get_hstring(ctx, -1);
32016 DUK_ASSERT(js_ctx->h_gap != NULL);
32017 } else {
32018 /* nop */
32019 }
32020
32021 if (js_ctx->h_gap != NULL) {
32022 /* if gap is empty, behave as if not given at all */
32023 if (DUK_HSTRING_GET_CHARLEN(js_ctx->h_gap) == 0) {
32024 js_ctx->h_gap = NULL;
7c673cae
FG
32025 }
32026 }
32027
7c673cae
FG
32028 /* [ ... buf loop (proplist) (gap) ] */
32029
32030 /*
32031 * Fast path: assume no mutation, iterate object property tables
32032 * directly; bail out if that assumption doesn't hold.
32033 */
32034
32035#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
11fdf7f2
TL
32036 if (js_ctx->h_replacer == NULL && /* replacer is a mutation risk */
32037 js_ctx->idx_proplist == -1) { /* proplist is very rare */
7c673cae
FG
32038 duk_int_t pcall_rc;
32039#ifdef DUK_USE_MARK_AND_SWEEP
32040 duk_small_uint_t prev_mark_and_sweep_base_flags;
32041#endif
32042
32043 DUK_DD(DUK_DDPRINT("try JSON.stringify() fast path"));
32044
32045 /* Use recursion_limit to ensure we don't overwrite js_ctx->visiting[]
32046 * array so we don't need two counter checks in the fast path. The
32047 * slow path has a much larger recursion limit which we'll use if
32048 * necessary.
32049 */
32050 DUK_ASSERT(DUK_USE_JSON_ENC_RECLIMIT >= DUK_JSON_ENC_LOOPARRAY);
32051 js_ctx->recursion_limit = DUK_JSON_ENC_LOOPARRAY;
32052 DUK_ASSERT(js_ctx->recursion_depth == 0);
32053
32054 /* Execute the fast path in a protected call. If any error is thrown,
32055 * fall back to the slow path. This includes e.g. recursion limit
32056 * because the fast path has a smaller recursion limit (and simpler,
32057 * limited loop detection).
32058 */
32059
32060 duk_push_pointer(ctx, (void *) js_ctx);
32061 duk_dup(ctx, idx_value);
32062
32063#if defined(DUK_USE_MARK_AND_SWEEP)
32064 /* Must prevent finalizers which may have arbitrary side effects. */
32065 prev_mark_and_sweep_base_flags = thr->heap->mark_and_sweep_base_flags;
32066 thr->heap->mark_and_sweep_base_flags |=
32067 DUK_MS_FLAG_NO_FINALIZERS | /* avoid attempts to add/remove object keys */
32068 DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid attempt to compact any objects */
32069#endif
32070
32071 pcall_rc = duk_safe_call(ctx, duk__json_stringify_fast, 2 /*nargs*/, 0 /*nret*/);
32072
32073#if defined(DUK_USE_MARK_AND_SWEEP)
32074 thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
32075#endif
32076 if (pcall_rc == DUK_EXEC_SUCCESS) {
32077 DUK_DD(DUK_DDPRINT("fast path successful"));
32078 DUK_BW_PUSH_AS_STRING(thr, &js_ctx->bw);
32079 goto replace_finished;
32080 }
32081
32082 /* We come here for actual aborts (like encountering .toJSON())
32083 * but also for recursion/loop errors. Bufwriter size can be
32084 * kept because we'll probably need at least as much as we've
32085 * allocated so far.
32086 */
11fdf7f2 32087 DUK_D(DUK_DPRINT("fast path failed, serialize using slow path instead"));
7c673cae
FG
32088 DUK_BW_RESET_SIZE(thr, &js_ctx->bw);
32089 js_ctx->recursion_depth = 0;
32090 }
32091#endif
32092
32093 /*
32094 * Create wrapper object and serialize
32095 */
32096
32097 idx_holder = duk_push_object(ctx);
32098 duk_dup(ctx, idx_value);
32099 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_EMPTY_STRING);
32100
32101 DUK_DDD(DUK_DDDPRINT("before: flags=0x%08lx, loop=%!T, replacer=%!O, "
11fdf7f2 32102 "proplist=%!T, gap=%!O, holder=%!T",
7c673cae
FG
32103 (unsigned long) js_ctx->flags,
32104 (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop),
32105 (duk_heaphdr *) js_ctx->h_replacer,
32106 (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(ctx, js_ctx->idx_proplist) : NULL),
32107 (duk_heaphdr *) js_ctx->h_gap,
7c673cae
FG
32108 (duk_tval *) duk_get_tval(ctx, -1)));
32109
32110 /* serialize the wrapper with empty string key */
32111
32112 duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
32113
32114 /* [ ... buf loop (proplist) (gap) holder "" ] */
32115
32116 js_ctx->recursion_limit = DUK_USE_JSON_ENC_RECLIMIT;
32117 DUK_ASSERT(js_ctx->recursion_depth == 0);
11fdf7f2
TL
32118
32119 if (DUK_UNLIKELY(duk__enc_value(js_ctx, idx_holder) == 0)) { /* [ ... holder key ] -> [ ... holder ] */
32120 /* Result is undefined. */
32121 duk_push_undefined(ctx);
32122 } else {
32123 /* Convert buffer to result string. */
32124 DUK_BW_PUSH_AS_STRING(thr, &js_ctx->bw);
32125 }
7c673cae
FG
32126
32127 DUK_DDD(DUK_DDDPRINT("after: flags=0x%08lx, loop=%!T, replacer=%!O, "
11fdf7f2 32128 "proplist=%!T, gap=%!O, holder=%!T",
7c673cae
FG
32129 (unsigned long) js_ctx->flags,
32130 (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop),
32131 (duk_heaphdr *) js_ctx->h_replacer,
32132 (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(ctx, js_ctx->idx_proplist) : NULL),
32133 (duk_heaphdr *) js_ctx->h_gap,
11fdf7f2 32134 (duk_tval *) duk_get_tval(ctx, idx_holder)));
7c673cae
FG
32135
32136 /* The stack has a variable shape here, so force it to the
32137 * desired one explicitly.
32138 */
32139
32140#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
32141 replace_finished:
32142#endif
32143 duk_replace(ctx, entry_top);
32144 duk_set_top(ctx, entry_top + 1);
32145
32146 DUK_DDD(DUK_DDDPRINT("JSON stringify end: value=%!T, replacer=%!T, space=%!T, "
32147 "flags=0x%08lx, result=%!T, stack_top=%ld",
32148 (duk_tval *) duk_get_tval(ctx, idx_value),
32149 (duk_tval *) duk_get_tval(ctx, idx_replacer),
32150 (duk_tval *) duk_get_tval(ctx, idx_space),
32151 (unsigned long) flags,
32152 (duk_tval *) duk_get_tval(ctx, -1),
32153 (long) duk_get_top(ctx)));
32154
32155 DUK_ASSERT(duk_get_top(ctx) == entry_top + 1);
32156}
32157
32158/*
32159 * Entry points
32160 */
32161
32162DUK_INTERNAL duk_ret_t duk_bi_json_object_parse(duk_context *ctx) {
32163 duk_bi_json_parse_helper(ctx,
32164 0 /*idx_value*/,
32165 1 /*idx_replacer*/,
32166 0 /*flags*/);
32167 return 1;
32168}
32169
32170DUK_INTERNAL duk_ret_t duk_bi_json_object_stringify(duk_context *ctx) {
32171 duk_bi_json_stringify_helper(ctx,
32172 0 /*idx_value*/,
32173 1 /*idx_replacer*/,
32174 2 /*idx_space*/,
32175 0 /*flags*/);
32176 return 1;
32177}
32178
32179#undef DUK__JSON_DECSTR_BUFSIZE
32180#undef DUK__JSON_DECSTR_CHUNKSIZE
32181#undef DUK__JSON_ENCSTR_CHUNKSIZE
32182#undef DUK__JSON_STRINGIFY_BUFSIZE
32183#undef DUK__JSON_MAX_ESC_LEN
7c673cae
FG
32184/*
32185 * Logging support
32186 */
32187
32188/* include removed: duk_internal.h */
32189
32190/* 3-letter log level strings */
32191DUK_LOCAL const duk_uint8_t duk__log_level_strings[] = {
32192 (duk_uint8_t) DUK_ASC_UC_T, (duk_uint8_t) DUK_ASC_UC_R, (duk_uint8_t) DUK_ASC_UC_C,
32193 (duk_uint8_t) DUK_ASC_UC_D, (duk_uint8_t) DUK_ASC_UC_B, (duk_uint8_t) DUK_ASC_UC_G,
32194 (duk_uint8_t) DUK_ASC_UC_I, (duk_uint8_t) DUK_ASC_UC_N, (duk_uint8_t) DUK_ASC_UC_F,
32195 (duk_uint8_t) DUK_ASC_UC_W, (duk_uint8_t) DUK_ASC_UC_R, (duk_uint8_t) DUK_ASC_UC_N,
32196 (duk_uint8_t) DUK_ASC_UC_E, (duk_uint8_t) DUK_ASC_UC_R, (duk_uint8_t) DUK_ASC_UC_R,
32197 (duk_uint8_t) DUK_ASC_UC_F, (duk_uint8_t) DUK_ASC_UC_T, (duk_uint8_t) DUK_ASC_UC_L
32198};
32199
32200/* Constructor */
32201DUK_INTERNAL duk_ret_t duk_bi_logger_constructor(duk_context *ctx) {
32202 duk_hthread *thr = (duk_hthread *) ctx;
32203 duk_idx_t nargs;
32204
32205 /* Calling as a non-constructor is not meaningful. */
32206 if (!duk_is_constructor_call(ctx)) {
32207 return DUK_RET_TYPE_ERROR;
32208 }
32209
32210 nargs = duk_get_top(ctx);
32211 duk_set_top(ctx, 1);
32212
32213 duk_push_this(ctx);
32214
32215 /* [ name this ] */
32216
32217 if (nargs == 0) {
32218 /* Automatic defaulting of logger name from caller. This would
32219 * work poorly with tail calls, but constructor calls are currently
32220 * never tail calls, so tail calls are not an issue now.
32221 */
32222
32223 if (thr->callstack_top >= 2) {
32224 duk_activation *act_caller = thr->callstack + thr->callstack_top - 2;
32225 duk_hobject *func_caller;
32226
32227 func_caller = DUK_ACT_GET_FUNC(act_caller);
32228 if (func_caller) {
32229 /* Stripping the filename might be a good idea
32230 * ("/foo/bar/quux.js" -> logger name "quux"),
32231 * but now used verbatim.
32232 */
32233 duk_push_hobject(ctx, func_caller);
32234 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_FILE_NAME);
32235 duk_replace(ctx, 0);
32236 }
32237 }
32238 }
32239 /* the stack is unbalanced here on purpose; we only rely on the
32240 * initial two values: [ name this ].
32241 */
32242
32243 if (duk_is_string(ctx, 0)) {
32244 duk_dup(ctx, 0);
32245 duk_put_prop_stridx(ctx, 1, DUK_STRIDX_LC_N);
32246 } else {
32247 /* don't set 'n' at all, inherited value is used as name */
32248 }
32249
32250 duk_compact(ctx, 1);
32251
32252 return 0; /* keep default instance */
32253}
32254
32255/* Default function to format objects. Tries to use toLogString() but falls
32256 * back to toString(). Any errors are propagated out without catching.
32257 */
32258DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_fmt(duk_context *ctx) {
32259 if (duk_get_prop_stridx(ctx, 0, DUK_STRIDX_TO_LOG_STRING)) {
32260 /* [ arg toLogString ] */
32261
32262 duk_dup(ctx, 0);
32263 duk_call_method(ctx, 0);
32264
32265 /* [ arg result ] */
32266 return 1;
32267 }
32268
32269 /* [ arg undefined ] */
32270 duk_pop(ctx);
32271 duk_to_string(ctx, 0);
32272 return 1;
32273}
32274
32275/* Default function to write a formatted log line. Writes to stderr,
32276 * appending a newline to the log line.
32277 *
32278 * The argument is a buffer whose visible size contains the log message.
32279 * This function should avoid coercing the buffer to a string to avoid
32280 * string table traffic.
32281 */
32282DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_raw(duk_context *ctx) {
32283 const char *data;
32284 duk_size_t data_len;
32285
32286 DUK_UNREF(ctx);
32287 DUK_UNREF(data);
32288 DUK_UNREF(data_len);
32289
32290#ifdef DUK_USE_FILE_IO
32291 data = (const char *) duk_require_buffer(ctx, 0, &data_len);
32292 DUK_FWRITE((const void *) data, 1, data_len, DUK_STDERR);
32293 DUK_FPUTC((int) '\n', DUK_STDERR);
32294 DUK_FFLUSH(DUK_STDERR);
32295#else
32296 /* nop */
32297#endif
32298 return 0;
32299}
32300
32301/* Log frontend shared helper, magic value indicates log level. Provides
32302 * frontend functions: trace(), debug(), info(), warn(), error(), fatal().
32303 * This needs to have small footprint, reasonable performance, minimal
32304 * memory churn, etc.
32305 */
32306DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_log_shared(duk_context *ctx) {
32307 duk_hthread *thr = (duk_hthread *) ctx;
32308 duk_double_t now;
32309 duk_small_int_t entry_lev = duk_get_current_magic(ctx);
32310 duk_small_int_t logger_lev;
32311 duk_int_t nargs;
32312 duk_int_t i;
32313 duk_size_t tot_len;
32314 const duk_uint8_t *arg_str;
32315 duk_size_t arg_len;
32316 duk_uint8_t *buf, *p;
32317 const duk_uint8_t *q;
32318 duk_uint8_t date_buf[DUK_BI_DATE_ISO8601_BUFSIZE];
32319 duk_size_t date_len;
32320 duk_small_int_t rc;
32321
32322 DUK_ASSERT(entry_lev >= 0 && entry_lev <= 5);
32323 DUK_UNREF(thr);
32324
32325 /* XXX: sanitize to printable (and maybe ASCII) */
32326 /* XXX: better multiline */
32327
32328 /*
32329 * Logger arguments are:
32330 *
32331 * magic: log level (0-5)
32332 * this: logger
32333 * stack: plain log args
32334 *
32335 * We want to minimize memory churn so a two-pass approach
32336 * is used: first pass formats arguments and computes final
32337 * string length, second pass copies strings either into a
32338 * pre-allocated and reused buffer (short messages) or into a
32339 * newly allocated fixed buffer. If the backend function plays
32340 * nice, it won't coerce the buffer to a string (and thus
32341 * intern it).
32342 */
32343
32344 nargs = duk_get_top(ctx);
32345
32346 /* [ arg1 ... argN this ] */
32347
32348 /*
32349 * Log level check
32350 */
32351
32352 duk_push_this(ctx);
32353
32354 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LC_L);
32355 logger_lev = (duk_small_int_t) duk_get_int(ctx, -1);
32356 if (entry_lev < logger_lev) {
32357 return 0;
32358 }
32359 /* log level could be popped but that's not necessary */
32360
32361 now = DUK_USE_DATE_GET_NOW(ctx);
32362 duk_bi_date_format_timeval(now, date_buf);
32363 date_len = DUK_STRLEN((const char *) date_buf);
32364
32365 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_LC_N);
32366 duk_to_string(ctx, -1);
32367 DUK_ASSERT(duk_is_string(ctx, -1));
32368
32369 /* [ arg1 ... argN this loggerLevel loggerName ] */
32370
32371 /*
32372 * Pass 1
32373 */
32374
32375 /* Line format: <time> <entryLev> <loggerName>: <msg> */
32376
32377 tot_len = 0;
32378 tot_len += 3 + /* separators: space, space, colon */
32379 3 + /* level string */
32380 date_len + /* time */
32381 duk_get_length(ctx, -1); /* loggerName */
32382
32383 for (i = 0; i < nargs; i++) {
32384 /* When formatting an argument to a string, errors may happen from multiple
32385 * causes. In general we want to catch obvious errors like a toLogString()
32386 * throwing an error, but we don't currently try to catch every possible
32387 * error. In particular, internal errors (like out of memory or stack) are
32388 * not caught. Also, we expect Error toString() to not throw an error.
32389 */
32390 if (duk_is_object(ctx, i)) {
32391 /* duk_pcall_prop() may itself throw an error, but we're content
32392 * in catching the obvious errors (like toLogString() throwing an
32393 * error).
32394 */
32395 duk_push_hstring_stridx(ctx, DUK_STRIDX_FMT);
32396 duk_dup(ctx, i);
32397 /* [ arg1 ... argN this loggerLevel loggerName 'fmt' arg ] */
32398 /* call: this.fmt(arg) */
32399 rc = duk_pcall_prop(ctx, -5 /*obj_index*/, 1 /*nargs*/);
32400 if (rc) {
32401 /* Keep the error as the result (coercing it might fail below,
32402 * but we don't catch that now).
32403 */
32404 ;
32405 }
32406 duk_replace(ctx, i);
32407 }
32408 (void) duk_to_lstring(ctx, i, &arg_len);
32409 tot_len++; /* sep (even before first one) */
32410 tot_len += arg_len;
32411 }
32412
32413 /*
32414 * Pass 2
32415 */
32416
32417 /* XXX: There used to be a shared log buffer here, but it was removed
32418 * when dynamic buffer spare was removed. The problem with using
32419 * bufwriter is that, without the spare, the buffer gets passed on
32420 * as an argument to the raw() call so it'd need to be resized
32421 * (reallocated) anyway. If raw() call convention is changed, this
32422 * could be made more efficient.
32423 */
32424
32425 buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, tot_len);
32426 DUK_ASSERT(buf != NULL);
32427 p = buf;
32428
11fdf7f2 32429 DUK_MEMCPY((void *) p, (const void *) date_buf, (size_t) date_len);
7c673cae
FG
32430 p += date_len;
32431 *p++ = (duk_uint8_t) DUK_ASC_SPACE;
32432
32433 q = duk__log_level_strings + (entry_lev * 3);
11fdf7f2 32434 DUK_MEMCPY((void *) p, (const void *) q, (size_t) 3);
7c673cae
FG
32435 p += 3;
32436
32437 *p++ = (duk_uint8_t) DUK_ASC_SPACE;
32438
32439 arg_str = (const duk_uint8_t *) duk_get_lstring(ctx, -2, &arg_len);
11fdf7f2 32440 DUK_MEMCPY((void *) p, (const void *) arg_str, (size_t) arg_len);
7c673cae
FG
32441 p += arg_len;
32442
32443 *p++ = (duk_uint8_t) DUK_ASC_COLON;
32444
32445 for (i = 0; i < nargs; i++) {
32446 *p++ = (duk_uint8_t) DUK_ASC_SPACE;
32447
32448 arg_str = (const duk_uint8_t *) duk_get_lstring(ctx, i, &arg_len);
32449 DUK_ASSERT(arg_str != NULL);
11fdf7f2 32450 DUK_MEMCPY((void *) p, (const void *) arg_str, (size_t) arg_len);
7c673cae
FG
32451 p += arg_len;
32452 }
32453 DUK_ASSERT(buf + tot_len == p);
32454
32455 /* [ arg1 ... argN this loggerLevel loggerName buffer ] */
32456
32457#if defined(DUK_USE_DEBUGGER_SUPPORT) && defined(DUK_USE_DEBUGGER_FWD_LOGGING)
32458 /* Do debugger forwarding before raw() because the raw() function
32459 * doesn't get the log level right now.
32460 */
32461 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
32462 const char *log_buf;
32463 duk_size_t sz_buf;
32464 log_buf = (const char *) duk_get_buffer(ctx, -1, &sz_buf);
32465 DUK_ASSERT(log_buf != NULL);
32466 duk_debug_write_notify(thr, DUK_DBG_CMD_LOG);
32467 duk_debug_write_int(thr, (duk_int32_t) entry_lev);
32468 duk_debug_write_string(thr, (const char *) log_buf, sz_buf);
32469 duk_debug_write_eom(thr);
32470 }
32471#endif
32472
32473 /* Call this.raw(msg); look up through the instance allows user to override
32474 * the raw() function in the instance or in the prototype for maximum
32475 * flexibility.
32476 */
32477 duk_push_hstring_stridx(ctx, DUK_STRIDX_RAW);
32478 duk_dup(ctx, -2);
32479 /* [ arg1 ... argN this loggerLevel loggerName buffer 'raw' buffer ] */
32480 duk_call_prop(ctx, -6, 1); /* this.raw(buffer) */
32481
32482 return 0;
32483}
7c673cae
FG
32484/*
32485 * Math built-ins
32486 */
32487
32488/* include removed: duk_internal.h */
32489
32490#if defined(DUK_USE_MATH_BUILTIN)
32491
32492/*
32493 * Use static helpers which can work with math.h functions matching
32494 * the following signatures. This is not portable if any of these math
32495 * functions is actually a macro.
32496 *
32497 * Typing here is intentionally 'double' wherever values interact with
32498 * the standard library APIs.
32499 */
32500
32501typedef double (*duk__one_arg_func)(double);
32502typedef double (*duk__two_arg_func)(double, double);
32503
32504DUK_LOCAL duk_ret_t duk__math_minmax(duk_context *ctx, duk_double_t initial, duk__two_arg_func min_max) {
32505 duk_idx_t n = duk_get_top(ctx);
32506 duk_idx_t i;
32507 duk_double_t res = initial;
32508 duk_double_t t;
32509
32510 /*
32511 * Note: fmax() does not match the E5 semantics. E5 requires
32512 * that if -any- input to Math.max() is a NaN, the result is a
32513 * NaN. fmax() will return a NaN only if -both- inputs are NaN.
32514 * Same applies to fmin().
32515 *
32516 * Note: every input value must be coerced with ToNumber(), even
32517 * if we know the result will be a NaN anyway: ToNumber() may have
32518 * side effects for which even order of evaluation matters.
32519 */
32520
32521 for (i = 0; i < n; i++) {
32522 t = duk_to_number(ctx, i);
32523 if (DUK_FPCLASSIFY(t) == DUK_FP_NAN || DUK_FPCLASSIFY(res) == DUK_FP_NAN) {
32524 /* Note: not normalized, but duk_push_number() will normalize */
32525 res = (duk_double_t) DUK_DOUBLE_NAN;
32526 } else {
32527 res = (duk_double_t) min_max(res, (double) t);
32528 }
32529 }
32530
32531 duk_push_number(ctx, res);
32532 return 1;
32533}
32534
32535DUK_LOCAL double duk__fmin_fixed(double x, double y) {
32536 /* fmin() with args -0 and +0 is not guaranteed to return
32537 * -0 as Ecmascript requires.
32538 */
32539 if (x == 0 && y == 0) {
32540 /* XXX: what's the safest way of creating a negative zero? */
32541 if (DUK_SIGNBIT(x) != 0 || DUK_SIGNBIT(y) != 0) {
32542 return -0.0;
32543 } else {
32544 return +0.0;
32545 }
32546 }
32547#ifdef DUK_USE_MATH_FMIN
32548 return DUK_FMIN(x, y);
32549#else
32550 return (x < y ? x : y);
32551#endif
32552}
32553
32554DUK_LOCAL double duk__fmax_fixed(double x, double y) {
32555 /* fmax() with args -0 and +0 is not guaranteed to return
32556 * +0 as Ecmascript requires.
32557 */
32558 if (x == 0 && y == 0) {
32559 if (DUK_SIGNBIT(x) == 0 || DUK_SIGNBIT(y) == 0) {
32560 return +0.0;
32561 } else {
32562 return -0.0;
32563 }
32564 }
32565#ifdef DUK_USE_MATH_FMAX
32566 return DUK_FMAX(x, y);
32567#else
32568 return (x > y ? x : y);
32569#endif
32570}
32571
32572DUK_LOCAL double duk__round_fixed(double x) {
32573 /* Numbers half-way between integers must be rounded towards +Infinity,
32574 * e.g. -3.5 must be rounded to -3 (not -4). When rounded to zero, zero
32575 * sign must be set appropriately. E5.1 Section 15.8.2.15.
32576 *
32577 * Note that ANSI C round() is "round to nearest integer, away from zero",
32578 * which is incorrect for negative values. Here we make do with floor().
32579 */
32580
32581 duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x);
32582 if (c == DUK_FP_NAN || c == DUK_FP_INFINITE || c == DUK_FP_ZERO) {
32583 return x;
32584 }
32585
32586 /*
32587 * x is finite and non-zero
32588 *
32589 * -1.6 -> floor(-1.1) -> -2
32590 * -1.5 -> floor(-1.0) -> -1 (towards +Inf)
32591 * -1.4 -> floor(-0.9) -> -1
32592 * -0.5 -> -0.0 (special case)
32593 * -0.1 -> -0.0 (special case)
32594 * +0.1 -> +0.0 (special case)
32595 * +0.5 -> floor(+1.0) -> 1 (towards +Inf)
32596 * +1.4 -> floor(+1.9) -> 1
32597 * +1.5 -> floor(+2.0) -> 2 (towards +Inf)
32598 * +1.6 -> floor(+2.1) -> 2
32599 */
32600
32601 if (x >= -0.5 && x < 0.5) {
32602 /* +0.5 is handled by floor, this is on purpose */
32603 if (x < 0.0) {
32604 return -0.0;
32605 } else {
32606 return +0.0;
32607 }
32608 }
32609
32610 return DUK_FLOOR(x + 0.5);
32611}
32612
32613DUK_LOCAL double duk__pow_fixed(double x, double y) {
32614 /* The ANSI C pow() semantics differ from Ecmascript.
32615 *
32616 * E.g. when x==1 and y is +/- infinite, the Ecmascript required
32617 * result is NaN, while at least Linux pow() returns 1.
32618 */
32619
32620 duk_small_int_t cx, cy, sx;
32621
32622 DUK_UNREF(cx);
32623 DUK_UNREF(sx);
32624 cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
32625
32626 if (cy == DUK_FP_NAN) {
32627 goto ret_nan;
32628 }
32629 if (DUK_FABS(x) == 1.0 && cy == DUK_FP_INFINITE) {
32630 goto ret_nan;
32631 }
32632#if defined(DUK_USE_POW_NETBSD_WORKAROUND)
32633 /* See test-bug-netbsd-math-pow.js: NetBSD 6.0 on x86 (at least) does not
32634 * correctly handle some cases where x=+/-0. Specific fixes to these
32635 * here.
32636 */
32637 cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
32638 if (cx == DUK_FP_ZERO && y < 0.0) {
32639 sx = (duk_small_int_t) DUK_SIGNBIT(x);
32640 if (sx == 0) {
32641 /* Math.pow(+0,y) should be Infinity when y<0. NetBSD pow()
32642 * returns -Infinity instead when y is <0 and finite. The
32643 * if-clause also catches y == -Infinity (which works even
32644 * without the fix).
32645 */
32646 return DUK_DOUBLE_INFINITY;
32647 } else {
32648 /* Math.pow(-0,y) where y<0 should be:
32649 * - -Infinity if y<0 and an odd integer
32650 * - Infinity otherwise
32651 * NetBSD pow() returns -Infinity for all finite y<0. The
32652 * if-clause also catches y == -Infinity (which works even
32653 * without the fix).
32654 */
32655
32656 /* fmod() return value has same sign as input (negative) so
32657 * the result here will be in the range ]-2,0], 1 indicates
32658 * odd. If x is -Infinity, NaN is returned and the odd check
32659 * always concludes "not odd" which results in desired outcome.
32660 */
32661 double tmp = DUK_FMOD(y, 2);
32662 if (tmp == -1.0) {
32663 return -DUK_DOUBLE_INFINITY;
32664 } else {
32665 /* Not odd, or y == -Infinity */
32666 return DUK_DOUBLE_INFINITY;
32667 }
32668 }
32669 }
32670#endif
32671 return DUK_POW(x, y);
32672
32673 ret_nan:
32674 return DUK_DOUBLE_NAN;
32675}
32676
32677/* Wrappers for calling standard math library methods. These may be required
32678 * on platforms where one or more of the math built-ins are defined as macros
32679 * or inline functions and are thus not suitable to be used as function pointers.
32680 */
32681#if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS)
32682DUK_LOCAL double duk__fabs(double x) {
32683 return DUK_FABS(x);
32684}
32685DUK_LOCAL double duk__acos(double x) {
32686 return DUK_ACOS(x);
32687}
32688DUK_LOCAL double duk__asin(double x) {
32689 return DUK_ASIN(x);
32690}
32691DUK_LOCAL double duk__atan(double x) {
32692 return DUK_ATAN(x);
32693}
32694DUK_LOCAL double duk__ceil(double x) {
32695 return DUK_CEIL(x);
32696}
32697DUK_LOCAL double duk__cos(double x) {
32698 return DUK_COS(x);
32699}
32700DUK_LOCAL double duk__exp(double x) {
32701 return DUK_EXP(x);
32702}
32703DUK_LOCAL double duk__floor(double x) {
32704 return DUK_FLOOR(x);
32705}
32706DUK_LOCAL double duk__log(double x) {
32707 return DUK_LOG(x);
32708}
32709DUK_LOCAL double duk__sin(double x) {
32710 return DUK_SIN(x);
32711}
32712DUK_LOCAL double duk__sqrt(double x) {
32713 return DUK_SQRT(x);
32714}
32715DUK_LOCAL double duk__tan(double x) {
32716 return DUK_TAN(x);
32717}
32718DUK_LOCAL double duk__atan2(double x, double y) {
32719 return DUK_ATAN2(x, y);
32720}
32721#endif /* DUK_USE_AVOID_PLATFORM_FUNCPTRS */
32722
32723/* order must match constants in genbuiltins.py */
32724DUK_LOCAL const duk__one_arg_func duk__one_arg_funcs[] = {
32725#if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS)
32726 duk__fabs,
32727 duk__acos,
32728 duk__asin,
32729 duk__atan,
32730 duk__ceil,
32731 duk__cos,
32732 duk__exp,
32733 duk__floor,
32734 duk__log,
32735 duk__round_fixed,
32736 duk__sin,
32737 duk__sqrt,
32738 duk__tan
32739#else
32740 DUK_FABS,
32741 DUK_ACOS,
32742 DUK_ASIN,
32743 DUK_ATAN,
32744 DUK_CEIL,
32745 DUK_COS,
32746 DUK_EXP,
32747 DUK_FLOOR,
32748 DUK_LOG,
32749 duk__round_fixed,
32750 DUK_SIN,
32751 DUK_SQRT,
32752 DUK_TAN
32753#endif
32754};
32755
32756/* order must match constants in genbuiltins.py */
32757DUK_LOCAL const duk__two_arg_func duk__two_arg_funcs[] = {
32758#if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS)
32759 duk__atan2,
32760 duk__pow_fixed
32761#else
32762 DUK_ATAN2,
32763 duk__pow_fixed
32764#endif
32765};
32766
32767DUK_INTERNAL duk_ret_t duk_bi_math_object_onearg_shared(duk_context *ctx) {
32768 duk_small_int_t fun_idx = duk_get_current_magic(ctx);
32769 duk__one_arg_func fun;
32770
32771 DUK_ASSERT(fun_idx >= 0);
32772 DUK_ASSERT(fun_idx < (duk_small_int_t) (sizeof(duk__one_arg_funcs) / sizeof(duk__one_arg_func)));
32773 fun = duk__one_arg_funcs[fun_idx];
32774 duk_push_number(ctx, (duk_double_t) fun((double) duk_to_number(ctx, 0)));
32775 return 1;
32776}
32777
32778DUK_INTERNAL duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx) {
32779 duk_small_int_t fun_idx = duk_get_current_magic(ctx);
32780 duk__two_arg_func fun;
32781
32782 DUK_ASSERT(fun_idx >= 0);
32783 DUK_ASSERT(fun_idx < (duk_small_int_t) (sizeof(duk__two_arg_funcs) / sizeof(duk__two_arg_func)));
32784 fun = duk__two_arg_funcs[fun_idx];
32785 duk_push_number(ctx, (duk_double_t) fun((double) duk_to_number(ctx, 0), (double) duk_to_number(ctx, 1)));
32786 return 1;
32787}
32788
32789DUK_INTERNAL duk_ret_t duk_bi_math_object_max(duk_context *ctx) {
32790 return duk__math_minmax(ctx, -DUK_DOUBLE_INFINITY, duk__fmax_fixed);
32791}
32792
32793DUK_INTERNAL duk_ret_t duk_bi_math_object_min(duk_context *ctx) {
32794 return duk__math_minmax(ctx, DUK_DOUBLE_INFINITY, duk__fmin_fixed);
32795}
32796
32797DUK_INTERNAL duk_ret_t duk_bi_math_object_random(duk_context *ctx) {
32798 duk_push_number(ctx, (duk_double_t) duk_util_tinyrandom_get_double((duk_hthread *) ctx));
32799 return 1;
32800}
32801
32802#else /* DUK_USE_MATH_BUILTIN */
32803
32804/* A stubbed built-in is useful for e.g. compilation torture testing with BCC. */
32805
32806DUK_INTERNAL duk_ret_t duk_bi_math_object_onearg_shared(duk_context *ctx) {
32807 DUK_UNREF(ctx);
32808 return DUK_RET_UNIMPLEMENTED_ERROR;
32809}
32810
32811DUK_INTERNAL duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx) {
32812 DUK_UNREF(ctx);
32813 return DUK_RET_UNIMPLEMENTED_ERROR;
32814}
32815
32816DUK_INTERNAL duk_ret_t duk_bi_math_object_max(duk_context *ctx) {
32817 DUK_UNREF(ctx);
32818 return DUK_RET_UNIMPLEMENTED_ERROR;
32819}
32820
32821DUK_INTERNAL duk_ret_t duk_bi_math_object_min(duk_context *ctx) {
32822 DUK_UNREF(ctx);
32823 return DUK_RET_UNIMPLEMENTED_ERROR;
32824}
32825
32826DUK_INTERNAL duk_ret_t duk_bi_math_object_random(duk_context *ctx) {
32827 DUK_UNREF(ctx);
32828 return DUK_RET_UNIMPLEMENTED_ERROR;
32829}
32830
32831#endif /* DUK_USE_MATH_BUILTIN */
7c673cae
FG
32832/*
32833 * Number built-ins
32834 */
32835
32836/* include removed: duk_internal.h */
32837
32838DUK_LOCAL duk_double_t duk__push_this_number_plain(duk_context *ctx) {
32839 duk_hobject *h;
32840
32841 /* Number built-in accepts a plain number or a Number object (whose
32842 * internal value is operated on). Other types cause TypeError.
32843 */
32844
32845 duk_push_this(ctx);
32846 if (duk_is_number(ctx, -1)) {
32847 DUK_DDD(DUK_DDDPRINT("plain number value: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
32848 goto done;
32849 }
32850 h = duk_get_hobject(ctx, -1);
32851 if (!h ||
32852 (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_NUMBER)) {
32853 DUK_DDD(DUK_DDDPRINT("unacceptable this value: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
11fdf7f2 32854 DUK_ERROR_TYPE((duk_hthread *) ctx, "number expected");
7c673cae
FG
32855 }
32856 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
32857 DUK_ASSERT(duk_is_number(ctx, -1));
32858 DUK_DDD(DUK_DDDPRINT("number object: %!T, internal value: %!T",
32859 (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1)));
32860 duk_remove(ctx, -2);
32861
32862 done:
32863 return duk_get_number(ctx, -1);
32864}
32865
32866DUK_INTERNAL duk_ret_t duk_bi_number_constructor(duk_context *ctx) {
32867 duk_hthread *thr = (duk_hthread *) ctx;
32868 duk_idx_t nargs;
32869 duk_hobject *h_this;
32870
32871 DUK_UNREF(thr);
32872
32873 /*
32874 * The Number constructor uses ToNumber(arg) for number coercion
32875 * (coercing an undefined argument to NaN). However, if the
32876 * argument is not given at all, +0 must be used instead. To do
32877 * this, a vararg function is used.
32878 */
32879
32880 nargs = duk_get_top(ctx);
32881 if (nargs == 0) {
32882 duk_push_int(ctx, 0);
32883 }
32884 duk_to_number(ctx, 0);
32885 duk_set_top(ctx, 1);
32886 DUK_ASSERT_TOP(ctx, 1);
32887
32888 if (!duk_is_constructor_call(ctx)) {
32889 return 1;
32890 }
32891
32892 /*
32893 * E5 Section 15.7.2.1 requires that the constructed object
32894 * must have the original Number.prototype as its internal
32895 * prototype. However, since Number.prototype is non-writable
32896 * and non-configurable, this doesn't have to be enforced here:
32897 * The default object (bound to 'this') is OK, though we have
32898 * to change its class.
32899 *
32900 * Internal value set to ToNumber(arg) or +0; if no arg given,
32901 * ToNumber(undefined) = NaN, so special treatment is needed
32902 * (above). String internal value is immutable.
32903 */
32904
32905 /* XXX: helper */
32906 duk_push_this(ctx);
32907 h_this = duk_get_hobject(ctx, -1);
32908 DUK_ASSERT(h_this != NULL);
32909 DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_NUMBER);
32910
32911 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_this) == thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE]);
32912 DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_this) == DUK_HOBJECT_CLASS_NUMBER);
32913 DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h_this));
32914
32915 duk_dup(ctx, 0); /* -> [ val obj val ] */
32916 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
32917 return 0; /* no return value -> don't replace created value */
32918}
32919
32920DUK_INTERNAL duk_ret_t duk_bi_number_prototype_value_of(duk_context *ctx) {
32921 (void) duk__push_this_number_plain(ctx);
32922 return 1;
32923}
32924
32925DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_string(duk_context *ctx) {
32926 duk_small_int_t radix;
32927 duk_small_uint_t n2s_flags;
32928
32929 (void) duk__push_this_number_plain(ctx);
32930 if (duk_is_undefined(ctx, 0)) {
32931 radix = 10;
32932 } else {
32933 radix = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 2, 36);
32934 }
32935 DUK_DDD(DUK_DDDPRINT("radix=%ld", (long) radix));
32936
32937 n2s_flags = 0;
32938
32939 duk_numconv_stringify(ctx,
32940 radix /*radix*/,
32941 0 /*digits*/,
32942 n2s_flags /*flags*/);
32943 return 1;
32944}
32945
32946DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_locale_string(duk_context *ctx) {
32947 /* XXX: just use toString() for now; permitted although not recommended.
32948 * nargs==1, so radix is passed to toString().
32949 */
32950 return duk_bi_number_prototype_to_string(ctx);
32951}
32952
32953/*
32954 * toFixed(), toExponential(), toPrecision()
32955 */
32956
32957/* XXX: shared helper for toFixed(), toExponential(), toPrecision()? */
32958
32959DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_fixed(duk_context *ctx) {
32960 duk_small_int_t frac_digits;
32961 duk_double_t d;
32962 duk_small_int_t c;
32963 duk_small_uint_t n2s_flags;
32964
32965 frac_digits = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 0, 20);
32966 d = duk__push_this_number_plain(ctx);
32967
32968 c = (duk_small_int_t) DUK_FPCLASSIFY(d);
32969 if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
32970 goto use_to_string;
32971 }
32972
32973 if (d >= 1.0e21 || d <= -1.0e21) {
32974 goto use_to_string;
32975 }
32976
32977 n2s_flags = DUK_N2S_FLAG_FIXED_FORMAT |
32978 DUK_N2S_FLAG_FRACTION_DIGITS;
32979
32980 duk_numconv_stringify(ctx,
32981 10 /*radix*/,
32982 frac_digits /*digits*/,
32983 n2s_flags /*flags*/);
32984 return 1;
32985
32986 use_to_string:
32987 DUK_ASSERT_TOP(ctx, 2);
32988 duk_to_string(ctx, -1);
32989 return 1;
32990}
32991
32992DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_exponential(duk_context *ctx) {
32993 duk_bool_t frac_undefined;
32994 duk_small_int_t frac_digits;
32995 duk_double_t d;
32996 duk_small_int_t c;
32997 duk_small_uint_t n2s_flags;
32998
32999 d = duk__push_this_number_plain(ctx);
33000
33001 frac_undefined = duk_is_undefined(ctx, 0);
33002 duk_to_int(ctx, 0); /* for side effects */
33003
33004 c = (duk_small_int_t) DUK_FPCLASSIFY(d);
33005 if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
33006 goto use_to_string;
33007 }
33008
33009 frac_digits = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 0, 20);
33010
33011 n2s_flags = DUK_N2S_FLAG_FORCE_EXP |
33012 (frac_undefined ? 0 : DUK_N2S_FLAG_FIXED_FORMAT);
33013
33014 duk_numconv_stringify(ctx,
33015 10 /*radix*/,
33016 frac_digits + 1 /*leading digit + fractions*/,
33017 n2s_flags /*flags*/);
33018 return 1;
33019
33020 use_to_string:
33021 DUK_ASSERT_TOP(ctx, 2);
33022 duk_to_string(ctx, -1);
33023 return 1;
33024}
33025
33026DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_precision(duk_context *ctx) {
33027 /* The specification has quite awkward order of coercion and
33028 * checks for toPrecision(). The operations below are a bit
33029 * reordered, within constraints of observable side effects.
33030 */
33031
33032 duk_double_t d;
33033 duk_small_int_t prec;
33034 duk_small_int_t c;
33035 duk_small_uint_t n2s_flags;
33036
33037 DUK_ASSERT_TOP(ctx, 1);
33038
33039 d = duk__push_this_number_plain(ctx);
33040 if (duk_is_undefined(ctx, 0)) {
33041 goto use_to_string;
33042 }
33043 DUK_ASSERT_TOP(ctx, 2);
33044
33045 duk_to_int(ctx, 0); /* for side effects */
33046
33047 c = (duk_small_int_t) DUK_FPCLASSIFY(d);
33048 if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
33049 goto use_to_string;
33050 }
33051
33052 prec = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 1, 21);
33053
33054 n2s_flags = DUK_N2S_FLAG_FIXED_FORMAT |
33055 DUK_N2S_FLAG_NO_ZERO_PAD;
33056
33057 duk_numconv_stringify(ctx,
33058 10 /*radix*/,
33059 prec /*digits*/,
33060 n2s_flags /*flags*/);
33061 return 1;
33062
33063 use_to_string:
33064 /* Used when precision is undefined; also used for NaN (-> "NaN"),
33065 * and +/- infinity (-> "Infinity", "-Infinity").
33066 */
33067
33068 DUK_ASSERT_TOP(ctx, 2);
33069 duk_to_string(ctx, -1);
33070 return 1;
33071}
7c673cae
FG
33072/*
33073 * Object built-ins
33074 */
33075
33076/* include removed: duk_internal.h */
33077
33078DUK_INTERNAL duk_ret_t duk_bi_object_constructor(duk_context *ctx) {
33079 if (!duk_is_constructor_call(ctx) &&
33080 !duk_is_null_or_undefined(ctx, 0)) {
33081 duk_to_object(ctx, 0);
33082 return 1;
33083 }
33084
33085 if (duk_is_object(ctx, 0)) {
33086 return 1;
33087 }
33088
33089 /* Pointer and buffer primitive values are treated like other
33090 * primitives values which have a fully fledged object counterpart:
33091 * promote to an object value. Lightfuncs are coerced with
33092 * ToObject() even they could also be returned as is.
33093 */
33094 if (duk_check_type_mask(ctx, 0, DUK_TYPE_MASK_STRING |
33095 DUK_TYPE_MASK_BOOLEAN |
33096 DUK_TYPE_MASK_NUMBER |
33097 DUK_TYPE_MASK_POINTER |
33098 DUK_TYPE_MASK_BUFFER |
33099 DUK_TYPE_MASK_LIGHTFUNC)) {
33100 duk_to_object(ctx, 0);
33101 return 1;
33102 }
33103
33104 duk_push_object_helper(ctx,
33105 DUK_HOBJECT_FLAG_EXTENSIBLE |
33106 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
33107 DUK_BIDX_OBJECT_PROTOTYPE);
33108 return 1;
33109}
33110
33111/* Shared helper to implement Object.getPrototypeOf and the ES6
33112 * Object.prototype.__proto__ getter.
33113 *
33114 * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__
33115 */
33116DUK_INTERNAL duk_ret_t duk_bi_object_getprototype_shared(duk_context *ctx) {
33117 duk_hthread *thr = (duk_hthread *) ctx;
33118 duk_hobject *h;
33119 duk_hobject *proto;
33120
33121 DUK_UNREF(thr);
33122
33123 /* magic: 0=getter call, 1=Object.getPrototypeOf */
33124 if (duk_get_current_magic(ctx) == 0) {
33125 duk_push_this_coercible_to_object(ctx);
33126 duk_insert(ctx, 0);
33127 }
33128
33129 h = duk_require_hobject_or_lfunc(ctx, 0);
33130 /* h is NULL for lightfunc */
33131
33132 /* XXX: should the API call handle this directly, i.e. attempt
33133 * to duk_push_hobject(ctx, null) would push a null instead?
33134 * (On the other hand 'undefined' would be just as logical, but
33135 * not wanted here.)
33136 */
33137
33138 if (h == NULL) {
33139 duk_push_hobject_bidx(ctx, DUK_BIDX_FUNCTION_PROTOTYPE);
33140 } else {
33141 proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
33142 if (proto) {
33143 duk_push_hobject(ctx, proto);
33144 } else {
33145 duk_push_null(ctx);
33146 }
33147 }
33148 return 1;
33149}
33150
33151/* Shared helper to implement ES6 Object.setPrototypeOf and
33152 * Object.prototype.__proto__ setter.
33153 *
33154 * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__
33155 * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-object.setprototypeof
33156 */
33157DUK_INTERNAL duk_ret_t duk_bi_object_setprototype_shared(duk_context *ctx) {
33158 duk_hthread *thr = (duk_hthread *) ctx;
33159 duk_hobject *h_obj;
33160 duk_hobject *h_new_proto;
33161 duk_hobject *h_curr;
33162 duk_ret_t ret_success = 1; /* retval for success path */
33163
33164 /* Preliminaries for __proto__ and setPrototypeOf (E6 19.1.2.18 steps 1-4);
33165 * magic: 0=setter call, 1=Object.setPrototypeOf
33166 */
33167 if (duk_get_current_magic(ctx) == 0) {
33168 duk_push_this_check_object_coercible(ctx);
33169 duk_insert(ctx, 0);
33170 if (!duk_check_type_mask(ctx, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT)) {
33171 return 0;
33172 }
33173
33174 /* __proto__ setter returns 'undefined' on success unlike the
33175 * setPrototypeOf() call which returns the target object.
33176 */
33177 ret_success = 0;
33178 } else {
33179 duk_require_object_coercible(ctx, 0);
33180 duk_require_type_mask(ctx, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT);
33181 }
33182
33183 h_new_proto = duk_get_hobject(ctx, 1);
33184 /* h_new_proto may be NULL */
33185 if (duk_is_lightfunc(ctx, 0)) {
33186 if (h_new_proto == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]) {
33187 goto skip;
33188 }
33189 goto fail_nonextensible;
33190 }
33191 h_obj = duk_get_hobject(ctx, 0);
33192 if (!h_obj) {
33193 goto skip;
33194 }
33195 DUK_ASSERT(h_obj != NULL);
33196
33197 /* [[SetPrototypeOf]] standard behavior, E6 9.1.2 */
33198 /* TODO: implement Proxy object support here */
33199
33200 if (h_new_proto == DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_obj)) {
33201 goto skip;
33202 }
33203 if (!DUK_HOBJECT_HAS_EXTENSIBLE(h_obj)) {
33204 goto fail_nonextensible;
33205 }
33206 for (h_curr = h_new_proto; h_curr != NULL; h_curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_curr)) {
33207 /* Loop prevention */
33208 if (h_curr == h_obj) {
33209 goto fail_loop;
33210 }
33211 }
33212 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h_obj, h_new_proto);
33213 /* fall thru */
33214
33215 skip:
33216 duk_set_top(ctx, 1);
33217 return ret_success;
33218
33219 fail_nonextensible:
33220 fail_loop:
33221 return DUK_RET_TYPE_ERROR;
33222}
33223
33224DUK_INTERNAL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_context *ctx) {
33225 /* XXX: no need for indirect call */
33226 return duk_hobject_object_get_own_property_descriptor(ctx);
33227}
33228
33229DUK_INTERNAL duk_ret_t duk_bi_object_constructor_create(duk_context *ctx) {
33230 duk_tval *tv;
33231 duk_hobject *proto = NULL;
33232
33233 DUK_ASSERT_TOP(ctx, 2);
33234
33235 tv = duk_get_tval(ctx, 0);
33236 DUK_ASSERT(tv != NULL);
33237 if (DUK_TVAL_IS_NULL(tv)) {
33238 ;
33239 } else if (DUK_TVAL_IS_OBJECT(tv)) {
33240 proto = DUK_TVAL_GET_OBJECT(tv);
33241 DUK_ASSERT(proto != NULL);
33242 } else {
33243 return DUK_RET_TYPE_ERROR;
33244 }
33245
33246 (void) duk_push_object_helper_proto(ctx,
33247 DUK_HOBJECT_FLAG_EXTENSIBLE |
33248 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
33249 proto);
33250
33251 if (!duk_is_undefined(ctx, 1)) {
33252 /* [ O Properties obj ] */
33253
33254 duk_replace(ctx, 0);
33255
33256 /* [ obj Properties ] */
33257
33258 /* Just call the "original" Object.defineProperties() to
33259 * finish up.
33260 */
33261
33262 return duk_bi_object_constructor_define_properties(ctx);
33263 }
33264
33265 /* [ O Properties obj ] */
33266
33267 return 1;
33268}
33269
33270DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_property(duk_context *ctx) {
33271 duk_hobject *obj;
33272 duk_hstring *key;
33273 duk_hobject *get;
33274 duk_hobject *set;
33275 duk_idx_t idx_value;
33276 duk_uint_t defprop_flags;
33277
33278 DUK_ASSERT(ctx != NULL);
33279
33280 DUK_DDD(DUK_DDDPRINT("Object.defineProperty(): ctx=%p obj=%!T key=%!T desc=%!T",
33281 (void *) ctx,
33282 (duk_tval *) duk_get_tval(ctx, 0),
33283 (duk_tval *) duk_get_tval(ctx, 1),
33284 (duk_tval *) duk_get_tval(ctx, 2)));
33285
33286 /* [ obj key desc ] */
33287
33288 /* Lightfuncs are currently supported by coercing to a temporary
33289 * Function object; changes will be allowed (the coerced value is
33290 * extensible) but will be lost.
33291 */
33292 obj = duk_require_hobject_or_lfunc_coerce(ctx, 0);
33293 (void) duk_to_string(ctx, 1);
33294 key = duk_require_hstring(ctx, 1);
33295 (void) duk_require_hobject(ctx, 2);
33296
33297 DUK_ASSERT(obj != NULL);
33298 DUK_ASSERT(key != NULL);
33299 DUK_ASSERT(duk_get_hobject(ctx, 2) != NULL);
33300
33301 /*
33302 * Validate and convert argument property descriptor (an Ecmascript
33303 * object) into a set of defprop_flags and possibly property value,
33304 * getter, and/or setter values on the value stack.
33305 *
33306 * Lightfunc set/get values are coerced to full Functions.
33307 */
33308
33309 duk_hobject_prepare_property_descriptor(ctx,
33310 2 /*idx_desc*/,
33311 &defprop_flags,
33312 &idx_value,
33313 &get,
33314 &set);
33315
33316 /*
33317 * Use Object.defineProperty() helper for the actual operation.
33318 */
33319
33320 duk_hobject_define_property_helper(ctx,
33321 defprop_flags,
33322 obj,
33323 key,
33324 idx_value,
33325 get,
33326 set);
33327
33328 /* Ignore the normalize/validate helper outputs on the value stack,
33329 * they're popped automatically.
33330 */
33331
33332 /*
33333 * Return target object.
33334 */
33335
33336 duk_push_hobject(ctx, obj);
33337 return 1;
33338}
33339
33340DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_properties(duk_context *ctx) {
33341 duk_small_uint_t pass;
33342 duk_uint_t defprop_flags;
33343 duk_hobject *obj;
33344 duk_idx_t idx_value;
33345 duk_hobject *get;
33346 duk_hobject *set;
33347
33348 /* Lightfunc handling by ToObject() coercion. */
33349 obj = duk_require_hobject_or_lfunc_coerce(ctx, 0); /* target */
33350 DUK_ASSERT(obj != NULL);
33351
33352 duk_to_object(ctx, 1); /* properties object */
33353
33354 DUK_DDD(DUK_DDDPRINT("target=%!iT, properties=%!iT",
33355 (duk_tval *) duk_get_tval(ctx, 0),
33356 (duk_tval *) duk_get_tval(ctx, 1)));
33357
33358 /*
33359 * Two pass approach to processing the property descriptors.
33360 * On first pass validate and normalize all descriptors before
33361 * any changes are made to the target object. On second pass
33362 * make the actual modifications to the target object.
33363 *
33364 * Right now we'll just use the same normalize/validate helper
33365 * on both passes, ignoring its outputs on the first pass.
33366 */
33367
33368 for (pass = 0; pass < 2; pass++) {
33369 duk_set_top(ctx, 2); /* -> [ hobject props ] */
33370 duk_enum(ctx, 1, DUK_ENUM_OWN_PROPERTIES_ONLY /*enum_flags*/);
33371
33372 for (;;) {
33373 duk_hstring *key;
33374
33375 /* [ hobject props enum(props) ] */
33376
33377 duk_set_top(ctx, 3);
33378
33379 if (!duk_next(ctx, 2, 1 /*get_value*/)) {
33380 break;
33381 }
33382
33383 DUK_DDD(DUK_DDDPRINT("-> key=%!iT, desc=%!iT",
33384 (duk_tval *) duk_get_tval(ctx, -2),
33385 (duk_tval *) duk_get_tval(ctx, -1)));
33386
33387 /* [ hobject props enum(props) key desc ] */
33388
33389 duk_hobject_prepare_property_descriptor(ctx,
33390 4 /*idx_desc*/,
33391 &defprop_flags,
33392 &idx_value,
33393 &get,
33394 &set);
33395
33396 /* [ hobject props enum(props) key desc value? getter? setter? ] */
33397
33398 if (pass == 0) {
33399 continue;
33400 }
33401
33402 key = duk_get_hstring(ctx, 3);
33403 DUK_ASSERT(key != NULL);
33404
33405 duk_hobject_define_property_helper(ctx,
33406 defprop_flags,
33407 obj,
33408 key,
33409 idx_value,
33410 get,
33411 set);
33412 }
33413 }
33414
33415 /*
33416 * Return target object
33417 */
33418
33419 duk_dup(ctx, 0);
33420 return 1;
33421}
33422
33423DUK_INTERNAL duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_context *ctx) {
33424 duk_hthread *thr = (duk_hthread *) ctx;
33425 duk_hobject *h;
33426 duk_bool_t is_freeze;
33427
33428 h = duk_require_hobject_or_lfunc(ctx, 0);
33429 if (!h) {
33430 /* Lightfunc, always success. */
33431 return 1;
33432 }
33433
33434 is_freeze = (duk_bool_t) duk_get_current_magic(ctx);
33435 duk_hobject_object_seal_freeze_helper(thr, h, is_freeze);
33436
33437 /* Sealed and frozen objects cannot gain any more properties,
33438 * so this is a good time to compact them.
33439 */
33440 duk_hobject_compact_props(thr, h);
33441
33442 return 1;
33443}
33444
33445DUK_INTERNAL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_context *ctx) {
33446 duk_hthread *thr = (duk_hthread *) ctx;
33447 duk_hobject *h;
33448
33449 h = duk_require_hobject_or_lfunc(ctx, 0);
33450 if (!h) {
33451 /* Lightfunc, always success. */
33452 return 1;
33453 }
33454 DUK_ASSERT(h != NULL);
33455
33456 DUK_HOBJECT_CLEAR_EXTENSIBLE(h);
33457
33458 /* A non-extensible object cannot gain any more properties,
33459 * so this is a good time to compact.
33460 */
33461 duk_hobject_compact_props(thr, h);
33462
33463 return 1;
33464}
33465
33466DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_context *ctx) {
33467 duk_hobject *h;
33468 duk_bool_t is_frozen;
33469 duk_bool_t rc;
33470
33471 h = duk_require_hobject_or_lfunc(ctx, 0);
33472 if (!h) {
33473 duk_push_true(ctx); /* frozen and sealed */
33474 } else {
33475 is_frozen = duk_get_current_magic(ctx);
33476 rc = duk_hobject_object_is_sealed_frozen_helper((duk_hthread *) ctx, h, is_frozen /*is_frozen*/);
33477 duk_push_boolean(ctx, rc);
33478 }
33479 return 1;
33480}
33481
33482DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_extensible(duk_context *ctx) {
33483 duk_hobject *h;
33484
33485 h = duk_require_hobject_or_lfunc(ctx, 0);
33486 if (!h) {
33487 duk_push_false(ctx);
33488 } else {
33489 duk_push_boolean(ctx, DUK_HOBJECT_HAS_EXTENSIBLE(h));
33490 }
33491 return 1;
33492}
33493
33494/* Shared helper for Object.getOwnPropertyNames() and Object.keys().
33495 * Magic: 0=getOwnPropertyNames, 1=Object.keys.
33496 */
33497DUK_INTERNAL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx) {
33498 duk_hthread *thr = (duk_hthread *) ctx;
33499 duk_hobject *obj;
33500#if defined(DUK_USE_ES6_PROXY)
33501 duk_hobject *h_proxy_target;
33502 duk_hobject *h_proxy_handler;
33503 duk_hobject *h_trap_result;
33504 duk_uarridx_t i, len, idx;
33505#endif
33506 duk_small_uint_t enum_flags;
33507
33508 DUK_ASSERT_TOP(ctx, 1);
33509 DUK_UNREF(thr);
33510
33511 obj = duk_require_hobject_or_lfunc_coerce(ctx, 0);
33512 DUK_ASSERT(obj != NULL);
33513 DUK_UNREF(obj);
33514
33515#if defined(DUK_USE_ES6_PROXY)
33516 if (DUK_LIKELY(!duk_hobject_proxy_check(thr,
33517 obj,
33518 &h_proxy_target,
33519 &h_proxy_handler))) {
33520 goto skip_proxy;
33521 }
33522
33523 duk_push_hobject(ctx, h_proxy_handler);
33524 if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_OWN_KEYS)) {
33525 /* Careful with reachability here: don't pop 'obj' before pushing
33526 * proxy target.
33527 */
33528 DUK_DDD(DUK_DDDPRINT("no ownKeys trap, get keys of target instead"));
33529 duk_pop_2(ctx);
33530 duk_push_hobject(ctx, h_proxy_target);
33531 duk_replace(ctx, 0);
33532 DUK_ASSERT_TOP(ctx, 1);
33533 goto skip_proxy;
33534 }
33535
33536 /* [ obj handler trap ] */
33537 duk_insert(ctx, -2);
33538 duk_push_hobject(ctx, h_proxy_target); /* -> [ obj trap handler target ] */
33539 duk_call_method(ctx, 1 /*nargs*/); /* -> [ obj trap_result ] */
33540 h_trap_result = duk_require_hobject(ctx, -1);
33541 DUK_UNREF(h_trap_result);
33542
33543 len = (duk_uarridx_t) duk_get_length(ctx, -1);
33544 idx = 0;
33545 duk_push_array(ctx);
33546 for (i = 0; i < len; i++) {
33547 /* [ obj trap_result res_arr ] */
33548 if (duk_get_prop_index(ctx, -2, i) && duk_is_string(ctx, -1)) {
33549 /* XXX: for Object.keys() we should check enumerability of key */
33550 /* [ obj trap_result res_arr propname ] */
33551 duk_put_prop_index(ctx, -2, idx);
33552 idx++;
33553 } else {
33554 duk_pop(ctx);
33555 }
33556 }
33557
11fdf7f2
TL
33558 /* XXX: missing trap result validation for non-configurable target keys
33559 * (must be present), for non-extensible target all target keys must be
33560 * present and no extra keys can be present.
33561 * http://www.ecma-international.org/ecma-262/6.0/#sec-proxy-object-internal-methods-and-internal-slots-ownpropertykeys
33562 */
33563
7c673cae
FG
33564 /* XXX: for Object.keys() the [[OwnPropertyKeys]] result (trap result)
33565 * should be filtered so that only enumerable keys remain. Enumerability
33566 * should be checked with [[GetOwnProperty]] on the original object
33567 * (i.e., the proxy in this case). If the proxy has a getOwnPropertyDescriptor
33568 * trap, it should be triggered for every property. If the proxy doesn't have
33569 * the trap, enumerability should be checked against the target object instead.
33570 * We don't do any of this now, so Object.keys() and Object.getOwnPropertyNames()
33571 * return the same result now for proxy traps. We still do clean up the trap
33572 * result, so that Object.keys() and Object.getOwnPropertyNames() will return a
33573 * clean array of strings without gaps.
33574 */
33575 return 1;
33576
33577 skip_proxy:
33578#endif /* DUK_USE_ES6_PROXY */
33579
33580 DUK_ASSERT_TOP(ctx, 1);
33581
33582 if (duk_get_current_magic(ctx)) {
33583 /* Object.keys */
33584 enum_flags = DUK_ENUM_OWN_PROPERTIES_ONLY |
33585 DUK_ENUM_NO_PROXY_BEHAVIOR;
33586 } else {
33587 /* Object.getOwnPropertyNames */
33588 enum_flags = DUK_ENUM_INCLUDE_NONENUMERABLE |
33589 DUK_ENUM_OWN_PROPERTIES_ONLY |
33590 DUK_ENUM_NO_PROXY_BEHAVIOR;
33591 }
33592
33593 return duk_hobject_get_enumerated_keys(ctx, enum_flags);
33594}
33595
33596DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_string(duk_context *ctx) {
7c673cae 33597 duk_push_this(ctx);
11fdf7f2 33598 duk_to_object_class_string_top(ctx);
7c673cae
FG
33599 return 1;
33600}
33601
33602DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_context *ctx) {
33603 DUK_ASSERT_TOP(ctx, 0);
33604 (void) duk_push_this_coercible_to_object(ctx);
33605 duk_get_prop_stridx(ctx, 0, DUK_STRIDX_TO_STRING);
33606 if (!duk_is_callable(ctx, 1)) {
33607 return DUK_RET_TYPE_ERROR;
33608 }
33609 duk_dup(ctx, 0); /* -> [ O toString O ] */
33610 duk_call_method(ctx, 0); /* XXX: call method tail call? */
33611 return 1;
33612}
33613
33614DUK_INTERNAL duk_ret_t duk_bi_object_prototype_value_of(duk_context *ctx) {
33615 (void) duk_push_this_coercible_to_object(ctx);
33616 return 1;
33617}
33618
33619DUK_INTERNAL duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_context *ctx) {
33620 duk_hthread *thr = (duk_hthread *) ctx;
33621 duk_hobject *h_v;
33622 duk_hobject *h_obj;
33623
33624 DUK_ASSERT_TOP(ctx, 1);
33625
33626 h_v = duk_get_hobject(ctx, 0);
33627 if (!h_v) {
33628 duk_push_false(ctx); /* XXX: tail call: return duk_push_false(ctx) */
33629 return 1;
33630 }
33631
33632 h_obj = duk_push_this_coercible_to_object(ctx);
33633 DUK_ASSERT(h_obj != NULL);
33634
33635 /* E5.1 Section 15.2.4.6, step 3.a, lookup proto once before compare.
33636 * Prototype loops should cause an error to be thrown.
33637 */
33638 duk_push_boolean(ctx, duk_hobject_prototype_chain_contains(thr, DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_v), h_obj, 0 /*ignore_loop*/));
33639 return 1;
33640}
33641
33642DUK_INTERNAL duk_ret_t duk_bi_object_prototype_has_own_property(duk_context *ctx) {
33643 return duk_hobject_object_ownprop_helper(ctx, 0 /*required_desc_flags*/);
33644}
33645
33646DUK_INTERNAL duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_context *ctx) {
33647 return duk_hobject_object_ownprop_helper(ctx, DUK_PROPDESC_FLAG_ENUMERABLE /*required_desc_flags*/);
33648}
7c673cae
FG
33649/*
33650 * Pointer built-ins
33651 */
33652
33653/* include removed: duk_internal.h */
33654
33655/*
33656 * Constructor
33657 */
33658
33659DUK_INTERNAL duk_ret_t duk_bi_pointer_constructor(duk_context *ctx) {
33660 /* XXX: this behavior is quite useless now; it would be nice to be able
33661 * to create pointer values from e.g. numbers or strings. Numbers are
33662 * problematic on 64-bit platforms though. Hex encoded strings?
33663 */
33664 if (duk_get_top(ctx) == 0) {
33665 duk_push_pointer(ctx, NULL);
33666 } else {
33667 duk_to_pointer(ctx, 0);
33668 }
33669 DUK_ASSERT(duk_is_pointer(ctx, 0));
33670 duk_set_top(ctx, 1);
33671
33672 if (duk_is_constructor_call(ctx)) {
33673 duk_push_object_helper(ctx,
33674 DUK_HOBJECT_FLAG_EXTENSIBLE |
33675 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER),
33676 DUK_BIDX_POINTER_PROTOTYPE);
33677
33678 /* Pointer object internal value is immutable */
33679 duk_dup(ctx, 0);
33680 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
33681 }
33682 /* Note: unbalanced stack on purpose */
33683
33684 return 1;
33685}
33686
33687/*
33688 * toString(), valueOf()
33689 */
33690
33691DUK_INTERNAL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_context *ctx) {
33692 duk_tval *tv;
33693 duk_small_int_t to_string = duk_get_current_magic(ctx);
33694
33695 duk_push_this(ctx);
33696 tv = duk_require_tval(ctx, -1);
33697 DUK_ASSERT(tv != NULL);
33698
33699 if (DUK_TVAL_IS_POINTER(tv)) {
33700 /* nop */
33701 } else if (DUK_TVAL_IS_OBJECT(tv)) {
33702 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
33703 DUK_ASSERT(h != NULL);
33704
33705 /* Must be a "pointer object", i.e. class "Pointer" */
33706 if (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_POINTER) {
33707 goto type_error;
33708 }
33709
33710 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
33711 } else {
33712 goto type_error;
33713 }
33714
33715 if (to_string) {
33716 duk_to_string(ctx, -1);
33717 }
33718 return 1;
33719
33720 type_error:
33721 return DUK_RET_TYPE_ERROR;
33722}
7c673cae
FG
33723/*
33724 * Proxy built-in (ES6)
33725 */
33726
33727/* include removed: duk_internal.h */
33728
33729#if defined(DUK_USE_ES6_PROXY)
33730DUK_INTERNAL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx) {
33731 duk_hobject *h_target;
33732 duk_hobject *h_handler;
33733
33734 if (!duk_is_constructor_call(ctx)) {
33735 return DUK_RET_TYPE_ERROR;
33736 }
33737
33738 /* Reject a proxy object as the target because it would need
33739 * special handler in property lookups. (ES6 has no such restriction)
33740 */
33741 h_target = duk_require_hobject_or_lfunc_coerce(ctx, 0);
33742 DUK_ASSERT(h_target != NULL);
33743 if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h_target)) {
33744 return DUK_RET_TYPE_ERROR;
33745 }
33746
33747 /* Reject a proxy object as the handler because it would cause
33748 * potentially unbounded recursion. (ES6 has no such restriction)
33749 */
33750 h_handler = duk_require_hobject_or_lfunc_coerce(ctx, 1);
33751 DUK_ASSERT(h_handler != NULL);
33752 if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h_handler)) {
33753 return DUK_RET_TYPE_ERROR;
33754 }
33755
33756 /* XXX: the returned value is exotic in ES6, but we use a
33757 * simple object here with no prototype. Without a prototype,
33758 * [[DefaultValue]] coercion fails which is abit confusing.
33759 * No callable check/handling in the current Proxy subset.
33760 */
33761 (void) duk_push_object_helper_proto(ctx,
33762 DUK_HOBJECT_FLAG_EXTENSIBLE |
33763 DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ |
33764 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
33765 NULL);
33766 DUK_ASSERT_TOP(ctx, 3);
33767
33768 /* Make _Target and _Handler non-configurable and non-writable.
33769 * They can still be forcibly changed by C code (both user and
33770 * Duktape internal), but not by Ecmascript code.
33771 */
33772
33773 /* Proxy target */
33774 duk_dup(ctx, 0);
33775 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
33776
33777 /* Proxy handler */
33778 duk_dup(ctx, 1);
33779 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_HANDLER, DUK_PROPDESC_FLAGS_NONE);
33780
33781 return 1; /* replacement handler */
33782}
33783#else /* DUK_USE_ES6_PROXY */
33784DUK_INTERNAL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx) {
33785 DUK_UNREF(ctx);
33786 return DUK_RET_UNSUPPORTED_ERROR;
33787}
33788#endif /* DUK_USE_ES6_PROXY */
7c673cae
FG
33789/*
33790 * RegExp built-ins
33791 */
33792
33793/* include removed: duk_internal.h */
33794
33795#ifdef DUK_USE_REGEXP_SUPPORT
33796
33797DUK_LOCAL void duk__get_this_regexp(duk_context *ctx) {
33798 duk_hobject *h;
33799
33800 duk_push_this(ctx);
33801 h = duk_require_hobject_with_class(ctx, -1, DUK_HOBJECT_CLASS_REGEXP);
33802 DUK_ASSERT(h != NULL);
33803 DUK_UNREF(h);
33804 duk_insert(ctx, 0); /* prepend regexp to valstack 0 index */
33805}
33806
33807/* XXX: much to improve (code size) */
33808DUK_INTERNAL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx) {
33809 duk_hthread *thr = (duk_hthread *) ctx;
33810 duk_hobject *h_pattern;
33811
33812 DUK_ASSERT_TOP(ctx, 2);
33813 h_pattern = duk_get_hobject(ctx, 0);
33814
33815 if (!duk_is_constructor_call(ctx) &&
33816 h_pattern != NULL &&
33817 DUK_HOBJECT_GET_CLASS_NUMBER(h_pattern) == DUK_HOBJECT_CLASS_REGEXP &&
33818 duk_is_undefined(ctx, 1)) {
33819 /* Called as a function, pattern has [[Class]] "RegExp" and
33820 * flags is undefined -> return object as is.
33821 */
33822 duk_dup(ctx, 0);
33823 return 1;
33824 }
33825
33826 /* Else functionality is identical for function call and constructor
33827 * call.
33828 */
33829
33830 if (h_pattern != NULL &&
33831 DUK_HOBJECT_GET_CLASS_NUMBER(h_pattern) == DUK_HOBJECT_CLASS_REGEXP) {
33832 if (duk_is_undefined(ctx, 1)) {
33833 duk_bool_t flag_g, flag_i, flag_m;
33834 duk_get_prop_stridx(ctx, 0, DUK_STRIDX_SOURCE);
33835 flag_g = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_GLOBAL, NULL);
33836 flag_i = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_IGNORE_CASE, NULL);
33837 flag_m = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_MULTILINE, NULL);
33838
33839 duk_push_sprintf(ctx, "%s%s%s",
33840 (const char *) (flag_g ? "g" : ""),
33841 (const char *) (flag_i ? "i" : ""),
33842 (const char *) (flag_m ? "m" : ""));
33843
33844 /* [ ... pattern flags ] */
33845 } else {
33846 return DUK_RET_TYPE_ERROR;
33847 }
33848 } else {
33849 if (duk_is_undefined(ctx, 0)) {
33850 duk_push_string(ctx, "");
33851 } else {
33852 duk_dup(ctx, 0);
33853 duk_to_string(ctx, -1);
33854 }
33855 if (duk_is_undefined(ctx, 1)) {
33856 duk_push_string(ctx, "");
33857 } else {
33858 duk_dup(ctx, 1);
33859 duk_to_string(ctx, -1);
33860 }
33861
33862 /* [ ... pattern flags ] */
33863 }
33864
33865 DUK_DDD(DUK_DDDPRINT("RegExp constructor/function call, pattern=%!T, flags=%!T",
33866 (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1)));
33867
33868 /* [ ... pattern flags ] */
33869
33870 duk_regexp_compile(thr);
33871
33872 /* [ ... bytecode escaped_source ] */
33873
33874 duk_regexp_create_instance(thr);
33875
33876 /* [ ... RegExp ] */
33877
33878 return 1;
33879}
33880
33881DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_exec(duk_context *ctx) {
33882 duk__get_this_regexp(ctx);
33883
33884 /* [ regexp input ] */
33885
33886 duk_regexp_match((duk_hthread *) ctx);
33887
33888 /* [ result ] */
33889
33890 return 1;
33891}
33892
33893DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_test(duk_context *ctx) {
33894 duk__get_this_regexp(ctx);
33895
33896 /* [ regexp input ] */
33897
33898 /* result object is created and discarded; wasteful but saves code space */
33899 duk_regexp_match((duk_hthread *) ctx);
33900
33901 /* [ result ] */
33902
33903 duk_push_boolean(ctx, (duk_is_null(ctx, -1) ? 0 : 1));
33904
33905 return 1;
33906}
33907
33908DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_to_string(duk_context *ctx) {
33909 duk_hstring *h_bc;
33910 duk_small_int_t re_flags;
33911
33912#if 0
33913 /* A little tricky string approach to provide the flags string.
33914 * This depends on the specific flag values in duk_regexp.h,
33915 * which needs to be asserted for. In practice this doesn't
33916 * produce more compact code than the easier approach in use.
33917 */
33918
33919 const char *flag_strings = "gim\0gi\0gm\0g\0";
33920 duk_uint8_t flag_offsets[8] = {
33921 (duk_uint8_t) 3, /* flags: "" */
33922 (duk_uint8_t) 10, /* flags: "g" */
33923 (duk_uint8_t) 5, /* flags: "i" */
33924 (duk_uint8_t) 4, /* flags: "gi" */
33925 (duk_uint8_t) 2, /* flags: "m" */
33926 (duk_uint8_t) 7, /* flags: "gm" */
33927 (duk_uint8_t) 1, /* flags: "im" */
33928 (duk_uint8_t) 0, /* flags: "gim" */
33929 };
33930 DUK_ASSERT(DUK_RE_FLAG_GLOBAL == 1);
33931 DUK_ASSERT(DUK_RE_FLAG_IGNORE_CASE == 2);
33932 DUK_ASSERT(DUK_RE_FLAG_MULTILINE == 4);
33933#endif
33934
33935 duk__get_this_regexp(ctx);
33936
33937 /* [ regexp ] */
33938
33939 duk_get_prop_stridx(ctx, 0, DUK_STRIDX_SOURCE);
33940 duk_get_prop_stridx(ctx, 0, DUK_STRIDX_INT_BYTECODE);
33941 h_bc = duk_get_hstring(ctx, -1);
33942 DUK_ASSERT(h_bc != NULL);
33943 DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(h_bc) >= 1);
33944 DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h_bc) >= 1);
33945 DUK_ASSERT(DUK_HSTRING_GET_DATA(h_bc)[0] < 0x80);
33946 re_flags = (duk_small_int_t) DUK_HSTRING_GET_DATA(h_bc)[0];
33947
33948 /* [ regexp source bytecode ] */
33949
33950#if 1
33951 /* This is a cleaner approach and also produces smaller code than
33952 * the other alternative. Use duk_require_string() for format
33953 * safety (although the source property should always exist).
33954 */
33955 duk_push_sprintf(ctx, "/%s/%s%s%s",
33956 (const char *) duk_require_string(ctx, -2), /* require to be safe */
33957 (re_flags & DUK_RE_FLAG_GLOBAL) ? "g" : "",
33958 (re_flags & DUK_RE_FLAG_IGNORE_CASE) ? "i" : "",
33959 (re_flags & DUK_RE_FLAG_MULTILINE) ? "m" : "");
33960#else
33961 /* This should not be necessary because no-one should tamper with the
33962 * regexp bytecode, but is prudent to avoid potential segfaults if that
33963 * were to happen for some reason.
33964 */
33965 re_flags &= 0x07;
33966 DUK_ASSERT(re_flags >= 0 && re_flags <= 7); /* three flags */
33967 duk_push_sprintf(ctx, "/%s/%s",
33968 (const char *) duk_require_string(ctx, -2),
33969 (const char *) (flag_strings + flag_offsets[re_flags]));
33970#endif
33971
33972 return 1;
33973}
33974
33975#else /* DUK_USE_REGEXP_SUPPORT */
33976
33977DUK_INTERNAL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx) {
33978 DUK_UNREF(ctx);
33979 return DUK_RET_UNSUPPORTED_ERROR;
33980}
33981
33982DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_exec(duk_context *ctx) {
33983 DUK_UNREF(ctx);
33984 return DUK_RET_UNSUPPORTED_ERROR;
33985}
33986
33987DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_test(duk_context *ctx) {
33988 DUK_UNREF(ctx);
33989 return DUK_RET_UNSUPPORTED_ERROR;
33990}
33991
33992DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_to_string(duk_context *ctx) {
33993 DUK_UNREF(ctx);
33994 return DUK_RET_UNSUPPORTED_ERROR;
33995}
33996
33997#endif /* DUK_USE_REGEXP_SUPPORT */
7c673cae
FG
33998/*
33999 * String built-ins
34000 */
34001
34002/* XXX: There are several limitations in the current implementation for
34003 * strings with >= 0x80000000UL characters. In some cases one would need
34004 * to be able to represent the range [-0xffffffff,0xffffffff] and so on.
34005 * Generally character and byte length are assumed to fit into signed 32
34006 * bits (< 0x80000000UL). Places with issues are not marked explicitly
34007 * below in all cases, look for signed type usage (duk_int_t etc) for
34008 * offsets/lengths.
34009 */
34010
34011/* include removed: duk_internal.h */
34012
34013/*
34014 * Constructor
34015 */
34016
34017DUK_INTERNAL duk_ret_t duk_bi_string_constructor(duk_context *ctx) {
34018 /* String constructor needs to distinguish between an argument not given at all
34019 * vs. given as 'undefined'. We're a vararg function to handle this properly.
34020 */
34021
34022 if (duk_get_top(ctx) == 0) {
34023 duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
34024 } else {
34025 duk_to_string(ctx, 0);
34026 }
34027 DUK_ASSERT(duk_is_string(ctx, 0));
34028 duk_set_top(ctx, 1);
34029
34030 if (duk_is_constructor_call(ctx)) {
34031 duk_push_object_helper(ctx,
34032 DUK_HOBJECT_FLAG_EXTENSIBLE |
34033 DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ |
34034 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING),
34035 DUK_BIDX_STRING_PROTOTYPE);
34036
34037 /* String object internal value is immutable */
34038 duk_dup(ctx, 0);
34039 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
34040 }
34041 /* Note: unbalanced stack on purpose */
34042
34043 return 1;
34044}
34045
34046DUK_INTERNAL duk_ret_t duk_bi_string_constructor_from_char_code(duk_context *ctx) {
34047 duk_hthread *thr = (duk_hthread *) ctx;
34048 duk_bufwriter_ctx bw_alloc;
34049 duk_bufwriter_ctx *bw;
34050 duk_idx_t i, n;
34051 duk_ucodepoint_t cp;
34052
34053 /* XXX: It would be nice to build the string directly but ToUint16()
34054 * coercion is needed so a generic helper would not be very
34055 * helpful (perhaps coerce the value stack first here and then
34056 * build a string from a duk_tval number sequence in one go?).
34057 */
34058
34059 n = duk_get_top(ctx);
34060
34061 bw = &bw_alloc;
34062 DUK_BW_INIT_PUSHBUF(thr, bw, n); /* initial estimate for ASCII only codepoints */
34063
34064 for (i = 0; i < n; i++) {
34065 /* XXX: could improve bufwriter handling to write multiple codepoints
34066 * with one ensure call but the relative benefit would be quite small.
34067 */
34068
34069#if defined(DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT)
34070 /* ToUint16() coercion is mandatory in the E5.1 specification, but
34071 * this non-compliant behavior makes more sense because we support
34072 * non-BMP codepoints. Don't use CESU-8 because that'd create
34073 * surrogate pairs.
34074 */
34075
34076 cp = (duk_ucodepoint_t) duk_to_uint32(ctx, i);
34077 DUK_BW_WRITE_ENSURE_XUTF8(thr, bw, cp);
34078#else
11fdf7f2 34079 cp = (duk_ucodepoint_t) duk_to_uint16(ctx, i);
7c673cae
FG
34080 DUK_BW_WRITE_ENSURE_CESU8(thr, bw, cp);
34081#endif
34082 }
34083
34084 DUK_BW_COMPACT(thr, bw);
34085 duk_to_string(ctx, -1);
34086 return 1;
34087}
34088
34089/*
34090 * toString(), valueOf()
34091 */
34092
34093DUK_INTERNAL duk_ret_t duk_bi_string_prototype_to_string(duk_context *ctx) {
34094 duk_tval *tv;
34095
34096 duk_push_this(ctx);
34097 tv = duk_require_tval(ctx, -1);
34098 DUK_ASSERT(tv != NULL);
34099
34100 if (DUK_TVAL_IS_STRING(tv)) {
34101 /* return as is */
34102 return 1;
34103 } else if (DUK_TVAL_IS_OBJECT(tv)) {
34104 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
34105 DUK_ASSERT(h != NULL);
34106
34107 /* Must be a "string object", i.e. class "String" */
34108 if (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_STRING) {
34109 goto type_error;
34110 }
34111
34112 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
34113 DUK_ASSERT(duk_is_string(ctx, -1));
34114
34115 return 1;
34116 } else {
34117 goto type_error;
34118 }
34119
34120 /* never here, but fall through */
34121
34122 type_error:
34123 return DUK_RET_TYPE_ERROR;
34124}
34125
34126/*
34127 * Character and charcode access
34128 */
34129
34130DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_at(duk_context *ctx) {
34131 duk_int_t pos;
34132
34133 /* XXX: faster implementation */
34134
34135 (void) duk_push_this_coercible_to_string(ctx);
34136 pos = duk_to_int(ctx, 0);
34137 duk_substring(ctx, -1, pos, pos + 1);
34138 return 1;
34139}
34140
34141DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_code_at(duk_context *ctx) {
34142 duk_hthread *thr = (duk_hthread *) ctx;
34143 duk_int_t pos;
34144 duk_hstring *h;
34145 duk_bool_t clamped;
34146
34147 /* XXX: faster implementation */
34148
34149 DUK_DDD(DUK_DDDPRINT("arg=%!T", (duk_tval *) duk_get_tval(ctx, 0)));
34150
34151 h = duk_push_this_coercible_to_string(ctx);
34152 DUK_ASSERT(h != NULL);
34153
34154 pos = duk_to_int_clamped_raw(ctx,
34155 0 /*index*/,
34156 0 /*min(incl)*/,
34157 DUK_HSTRING_GET_CHARLEN(h) - 1 /*max(incl)*/,
34158 &clamped /*out_clamped*/);
34159 if (clamped) {
34160 duk_push_number(ctx, DUK_DOUBLE_NAN);
34161 return 1;
34162 }
34163
34164 duk_push_u32(ctx, (duk_uint32_t) duk_hstring_char_code_at_raw(thr, h, pos));
34165 return 1;
34166}
34167
34168/*
34169 * substring(), substr(), slice()
34170 */
34171
34172/* XXX: any chance of merging these three similar but still slightly
34173 * different algorithms so that footprint would be reduced?
34174 */
34175
34176DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substring(duk_context *ctx) {
34177 duk_hstring *h;
34178 duk_int_t start_pos, end_pos;
34179 duk_int_t len;
34180
34181 h = duk_push_this_coercible_to_string(ctx);
34182 DUK_ASSERT(h != NULL);
34183 len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
34184
34185 /* [ start end str ] */
34186
34187 start_pos = duk_to_int_clamped(ctx, 0, 0, len);
34188 if (duk_is_undefined(ctx, 1)) {
34189 end_pos = len;
34190 } else {
34191 end_pos = duk_to_int_clamped(ctx, 1, 0, len);
34192 }
34193 DUK_ASSERT(start_pos >= 0 && start_pos <= len);
34194 DUK_ASSERT(end_pos >= 0 && end_pos <= len);
34195
34196 if (start_pos > end_pos) {
34197 duk_int_t tmp = start_pos;
34198 start_pos = end_pos;
34199 end_pos = tmp;
34200 }
34201
34202 DUK_ASSERT(end_pos >= start_pos);
34203
34204 duk_substring(ctx, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
34205 return 1;
34206}
34207
34208#ifdef DUK_USE_SECTION_B
34209DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx) {
34210 duk_hstring *h;
34211 duk_int_t start_pos, end_pos;
34212 duk_int_t len;
34213
34214 /* Unlike non-obsolete String calls, substr() algorithm in E5.1
34215 * specification will happily coerce undefined and null to strings
34216 * ("undefined" and "null").
34217 */
34218 duk_push_this(ctx);
34219 h = duk_to_hstring(ctx, -1);
34220 DUK_ASSERT(h != NULL);
34221 len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
34222
34223 /* [ start length str ] */
34224
34225 /* The implementation for computing of start_pos and end_pos differs
34226 * from the standard algorithm, but is intended to result in the exactly
34227 * same behavior. This is not always obvious.
34228 */
34229
34230 /* combines steps 2 and 5; -len ensures max() not needed for step 5 */
34231 start_pos = duk_to_int_clamped(ctx, 0, -len, len);
34232 if (start_pos < 0) {
34233 start_pos = len + start_pos;
34234 }
34235 DUK_ASSERT(start_pos >= 0 && start_pos <= len);
34236
34237 /* combines steps 3, 6; step 7 is not needed */
34238 if (duk_is_undefined(ctx, 1)) {
34239 end_pos = len;
34240 } else {
34241 DUK_ASSERT(start_pos <= len);
34242 end_pos = start_pos + duk_to_int_clamped(ctx, 1, 0, len - start_pos);
34243 }
34244 DUK_ASSERT(start_pos >= 0 && start_pos <= len);
34245 DUK_ASSERT(end_pos >= 0 && end_pos <= len);
34246 DUK_ASSERT(end_pos >= start_pos);
34247
34248 duk_substring(ctx, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
34249 return 1;
34250}
34251#else /* DUK_USE_SECTION_B */
34252DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx) {
34253 DUK_UNREF(ctx);
34254 return DUK_RET_UNSUPPORTED_ERROR;
34255}
34256#endif /* DUK_USE_SECTION_B */
34257
34258DUK_INTERNAL duk_ret_t duk_bi_string_prototype_slice(duk_context *ctx) {
34259 duk_hstring *h;
34260 duk_int_t start_pos, end_pos;
34261 duk_int_t len;
34262
34263 h = duk_push_this_coercible_to_string(ctx);
34264 DUK_ASSERT(h != NULL);
34265 len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
34266
34267 /* [ start end str ] */
34268
34269 start_pos = duk_to_int_clamped(ctx, 0, -len, len);
34270 if (start_pos < 0) {
34271 start_pos = len + start_pos;
34272 }
34273 if (duk_is_undefined(ctx, 1)) {
34274 end_pos = len;
34275 } else {
34276 end_pos = duk_to_int_clamped(ctx, 1, -len, len);
34277 if (end_pos < 0) {
34278 end_pos = len + end_pos;
34279 }
34280 }
34281 DUK_ASSERT(start_pos >= 0 && start_pos <= len);
34282 DUK_ASSERT(end_pos >= 0 && end_pos <= len);
34283
34284 if (end_pos < start_pos) {
34285 end_pos = start_pos;
34286 }
34287
34288 DUK_ASSERT(end_pos >= start_pos);
34289
34290 duk_substring(ctx, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
34291 return 1;
34292}
34293
34294/*
34295 * Case conversion
34296 */
34297
34298DUK_INTERNAL duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_context *ctx) {
34299 duk_hthread *thr = (duk_hthread *) ctx;
34300 duk_small_int_t uppercase = duk_get_current_magic(ctx);
34301
34302 (void) duk_push_this_coercible_to_string(ctx);
34303 duk_unicode_case_convert_string(thr, (duk_bool_t) uppercase);
34304 return 1;
34305}
34306
34307/*
34308 * indexOf() and lastIndexOf()
34309 */
34310
34311DUK_INTERNAL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_context *ctx) {
34312 duk_hthread *thr = (duk_hthread *) ctx;
34313 duk_hstring *h_this;
34314 duk_hstring *h_search;
34315 duk_int_t clen_this;
34316 duk_int_t cpos;
34317 duk_int_t bpos;
34318 const duk_uint8_t *p_start, *p_end, *p;
34319 const duk_uint8_t *q_start;
34320 duk_int_t q_blen;
34321 duk_uint8_t firstbyte;
34322 duk_uint8_t t;
34323 duk_small_int_t is_lastindexof = duk_get_current_magic(ctx); /* 0=indexOf, 1=lastIndexOf */
34324
34325 h_this = duk_push_this_coercible_to_string(ctx);
34326 DUK_ASSERT(h_this != NULL);
34327 clen_this = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h_this);
34328
34329 h_search = duk_to_hstring(ctx, 0);
34330 DUK_ASSERT(h_search != NULL);
34331 q_start = DUK_HSTRING_GET_DATA(h_search);
34332 q_blen = (duk_int_t) DUK_HSTRING_GET_BYTELEN(h_search);
34333
34334 duk_to_number(ctx, 1);
34335 if (duk_is_nan(ctx, 1) && is_lastindexof) {
34336 /* indexOf: NaN should cause pos to be zero.
34337 * lastIndexOf: NaN should cause pos to be +Infinity
34338 * (and later be clamped to len).
34339 */
34340 cpos = clen_this;
34341 } else {
34342 cpos = duk_to_int_clamped(ctx, 1, 0, clen_this);
34343 }
34344
34345 /* Empty searchstring always matches; cpos must be clamped here.
34346 * (If q_blen were < 0 due to clamped coercion, it would also be
34347 * caught here.)
34348 */
34349 if (q_blen <= 0) {
34350 duk_push_int(ctx, cpos);
34351 return 1;
34352 }
34353 DUK_ASSERT(q_blen > 0);
34354
34355 bpos = (duk_int_t) duk_heap_strcache_offset_char2byte(thr, h_this, (duk_uint32_t) cpos);
34356
34357 p_start = DUK_HSTRING_GET_DATA(h_this);
34358 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_this);
34359 p = p_start + bpos;
34360
34361 /* This loop is optimized for size. For speed, there should be
34362 * two separate loops, and we should ensure that memcmp() can be
34363 * used without an extra "will searchstring fit" check. Doing
34364 * the preconditioning for 'p' and 'p_end' is easy but cpos
34365 * must be updated if 'p' is wound back (backward scanning).
34366 */
34367
34368 firstbyte = q_start[0]; /* leading byte of match string */
34369 while (p <= p_end && p >= p_start) {
34370 t = *p;
34371
34372 /* For Ecmascript strings, this check can only match for
34373 * initial UTF-8 bytes (not continuation bytes). For other
34374 * strings all bets are off.
34375 */
34376
34377 if ((t == firstbyte) && ((duk_size_t) (p_end - p) >= (duk_size_t) q_blen)) {
34378 DUK_ASSERT(q_blen > 0); /* no issues with memcmp() zero size, even if broken */
11fdf7f2 34379 if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
7c673cae
FG
34380 duk_push_int(ctx, cpos);
34381 return 1;
34382 }
34383 }
34384
34385 /* track cpos while scanning */
34386 if (is_lastindexof) {
34387 /* when going backwards, we decrement cpos 'early';
34388 * 'p' may point to a continuation byte of the char
34389 * at offset 'cpos', but that's OK because we'll
34390 * backtrack all the way to the initial byte.
34391 */
34392 if ((t & 0xc0) != 0x80) {
34393 cpos--;
34394 }
34395 p--;
34396 } else {
34397 if ((t & 0xc0) != 0x80) {
34398 cpos++;
34399 }
34400 p++;
34401 }
34402 }
34403
34404 /* Not found. Empty string case is handled specially above. */
34405 duk_push_int(ctx, -1);
34406 return 1;
34407}
34408
34409/*
34410 * replace()
34411 */
34412
34413/* XXX: the current implementation works but is quite clunky; it compiles
34414 * to almost 1,4kB of x86 code so it needs to be simplified (better approach,
34415 * shared helpers, etc). Some ideas for refactoring:
34416 *
34417 * - a primitive to convert a string into a regexp matcher (reduces matching
34418 * code at the cost of making matching much slower)
34419 * - use replace() as a basic helper for match() and split(), which are both
34420 * much simpler
34421 * - API call to get_prop and to_boolean
34422 */
34423
34424DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
34425 duk_hthread *thr = (duk_hthread *) ctx;
34426 duk_hstring *h_input;
34427 duk_hstring *h_match;
34428 duk_hstring *h_search;
34429 duk_hobject *h_re;
34430 duk_bufwriter_ctx bw_alloc;
34431 duk_bufwriter_ctx *bw;
34432#ifdef DUK_USE_REGEXP_SUPPORT
34433 duk_bool_t is_regexp;
34434 duk_bool_t is_global;
34435#endif
34436 duk_bool_t is_repl_func;
34437 duk_uint32_t match_start_coff, match_start_boff;
34438#ifdef DUK_USE_REGEXP_SUPPORT
34439 duk_int_t match_caps;
34440#endif
34441 duk_uint32_t prev_match_end_boff;
34442 const duk_uint8_t *r_start, *r_end, *r; /* repl string scan */
34443 duk_size_t tmp_sz;
34444
34445 DUK_ASSERT_TOP(ctx, 2);
34446 h_input = duk_push_this_coercible_to_string(ctx);
34447 DUK_ASSERT(h_input != NULL);
34448
34449 bw = &bw_alloc;
34450 DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); /* input size is good output starting point */
34451
34452 DUK_ASSERT_TOP(ctx, 4);
34453
34454 /* stack[0] = search value
34455 * stack[1] = replace value
34456 * stack[2] = input string
34457 * stack[3] = result buffer
34458 */
34459
34460 h_re = duk_get_hobject_with_class(ctx, 0, DUK_HOBJECT_CLASS_REGEXP);
34461 if (h_re) {
34462#ifdef DUK_USE_REGEXP_SUPPORT
34463 is_regexp = 1;
34464 is_global = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_GLOBAL, NULL);
34465
34466 if (is_global) {
34467 /* start match from beginning */
34468 duk_push_int(ctx, 0);
34469 duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
34470 }
34471#else /* DUK_USE_REGEXP_SUPPORT */
34472 return DUK_RET_UNSUPPORTED_ERROR;
34473#endif /* DUK_USE_REGEXP_SUPPORT */
34474 } else {
34475 duk_to_string(ctx, 0);
34476#ifdef DUK_USE_REGEXP_SUPPORT
34477 is_regexp = 0;
34478 is_global = 0;
34479#endif
34480 }
34481
34482 if (duk_is_function(ctx, 1)) {
34483 is_repl_func = 1;
34484 r_start = NULL;
34485 r_end = NULL;
34486 } else {
34487 duk_hstring *h_repl;
34488
34489 is_repl_func = 0;
34490 h_repl = duk_to_hstring(ctx, 1);
34491 DUK_ASSERT(h_repl != NULL);
34492 r_start = DUK_HSTRING_GET_DATA(h_repl);
34493 r_end = r_start + DUK_HSTRING_GET_BYTELEN(h_repl);
34494 }
34495
34496 prev_match_end_boff = 0;
34497
34498 for (;;) {
34499 /*
34500 * If matching with a regexp:
34501 * - non-global RegExp: lastIndex not touched on a match, zeroed
34502 * on a non-match
34503 * - global RegExp: on match, lastIndex will be updated by regexp
34504 * executor to point to next char after the matching part (so that
34505 * characters in the matching part are not matched again)
34506 *
34507 * If matching with a string:
34508 * - always non-global match, find first occurrence
34509 *
34510 * We need:
34511 * - The character offset of start-of-match for the replacer function
34512 * - The byte offsets for start-of-match and end-of-match to implement
34513 * the replacement values $&, $`, and $', and to copy non-matching
34514 * input string portions (including header and trailer) verbatim.
34515 *
34516 * NOTE: the E5.1 specification is a bit vague how the RegExp should
34517 * behave in the replacement process; e.g. is matching done first for
34518 * all matches (in the global RegExp case) before any replacer calls
34519 * are made? See: test-bi-string-proto-replace.js for discussion.
34520 */
34521
34522 DUK_ASSERT_TOP(ctx, 4);
34523
34524#ifdef DUK_USE_REGEXP_SUPPORT
34525 if (is_regexp) {
34526 duk_dup(ctx, 0);
34527 duk_dup(ctx, 2);
34528 duk_regexp_match(thr); /* [ ... regexp input ] -> [ res_obj ] */
34529 if (!duk_is_object(ctx, -1)) {
34530 duk_pop(ctx);
34531 break;
34532 }
34533
34534 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INDEX);
34535 DUK_ASSERT(duk_is_number(ctx, -1));
34536 match_start_coff = duk_get_int(ctx, -1);
34537 duk_pop(ctx);
34538
34539 duk_get_prop_index(ctx, -1, 0);
34540 DUK_ASSERT(duk_is_string(ctx, -1));
34541 h_match = duk_get_hstring(ctx, -1);
34542 DUK_ASSERT(h_match != NULL);
34543 duk_pop(ctx); /* h_match is borrowed, remains reachable through match_obj */
34544
34545 if (DUK_HSTRING_GET_BYTELEN(h_match) == 0) {
34546 /* This should be equivalent to match() algorithm step 8.f.iii.2:
34547 * detect an empty match and allow it, but don't allow it twice.
34548 */
34549 duk_uint32_t last_index;
34550
34551 duk_get_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
34552 last_index = (duk_uint32_t) duk_get_uint(ctx, -1);
34553 DUK_DDD(DUK_DDDPRINT("empty match, bump lastIndex: %ld -> %ld",
34554 (long) last_index, (long) (last_index + 1)));
34555 duk_pop(ctx);
34556 duk_push_int(ctx, last_index + 1);
34557 duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
34558 }
34559
34560 DUK_ASSERT(duk_get_length(ctx, -1) <= DUK_INT_MAX); /* string limits */
34561 match_caps = (duk_int_t) duk_get_length(ctx, -1);
34562 } else {
34563#else /* DUK_USE_REGEXP_SUPPORT */
34564 { /* unconditionally */
34565#endif /* DUK_USE_REGEXP_SUPPORT */
34566 const duk_uint8_t *p_start, *p_end, *p; /* input string scan */
34567 const duk_uint8_t *q_start; /* match string */
34568 duk_size_t q_blen;
34569
34570#ifdef DUK_USE_REGEXP_SUPPORT
34571 DUK_ASSERT(!is_global); /* single match always */
34572#endif
34573
34574 p_start = DUK_HSTRING_GET_DATA(h_input);
34575 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
34576 p = p_start;
34577
34578 h_search = duk_get_hstring(ctx, 0);
34579 DUK_ASSERT(h_search != NULL);
34580 q_start = DUK_HSTRING_GET_DATA(h_search);
34581 q_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_search);
34582
34583 p_end -= q_blen; /* ensure full memcmp() fits in while */
34584
34585 match_start_coff = 0;
34586
34587 while (p <= p_end) {
34588 DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input));
11fdf7f2 34589 if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
7c673cae
FG
34590 duk_dup(ctx, 0);
34591 h_match = duk_get_hstring(ctx, -1);
34592 DUK_ASSERT(h_match != NULL);
34593#ifdef DUK_USE_REGEXP_SUPPORT
34594 match_caps = 0;
34595#endif
34596 goto found;
34597 }
34598
34599 /* track utf-8 non-continuation bytes */
34600 if ((p[0] & 0xc0) != 0x80) {
34601 match_start_coff++;
34602 }
34603 p++;
34604 }
34605
34606 /* not found */
34607 break;
34608 }
34609 found:
34610
34611 /* stack[0] = search value
34612 * stack[1] = replace value
34613 * stack[2] = input string
34614 * stack[3] = result buffer
34615 * stack[4] = regexp match OR match string
34616 */
34617
34618 match_start_boff = duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff);
34619
34620 tmp_sz = (duk_size_t) (match_start_boff - prev_match_end_boff);
34621 DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff, tmp_sz);
34622
34623 prev_match_end_boff = match_start_boff + DUK_HSTRING_GET_BYTELEN(h_match);
34624
34625 if (is_repl_func) {
34626 duk_idx_t idx_args;
34627 duk_hstring *h_repl;
34628
34629 /* regexp res_obj is at index 4 */
34630
34631 duk_dup(ctx, 1);
34632 idx_args = duk_get_top(ctx);
34633
34634#ifdef DUK_USE_REGEXP_SUPPORT
34635 if (is_regexp) {
34636 duk_int_t idx;
34637 duk_require_stack(ctx, match_caps + 2);
34638 for (idx = 0; idx < match_caps; idx++) {
34639 /* match followed by capture(s) */
34640 duk_get_prop_index(ctx, 4, idx);
34641 }
34642 } else {
34643#else /* DUK_USE_REGEXP_SUPPORT */
34644 { /* unconditionally */
34645#endif /* DUK_USE_REGEXP_SUPPORT */
34646 /* match == search string, by definition */
34647 duk_dup(ctx, 0);
34648 }
34649 duk_push_int(ctx, match_start_coff);
34650 duk_dup(ctx, 2);
34651
34652 /* [ ... replacer match [captures] match_char_offset input ] */
34653
34654 duk_call(ctx, duk_get_top(ctx) - idx_args);
34655 h_repl = duk_to_hstring(ctx, -1); /* -> [ ... repl_value ] */
34656 DUK_ASSERT(h_repl != NULL);
34657
34658 DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_repl);
34659
34660 duk_pop(ctx); /* repl_value */
34661 } else {
34662 r = r_start;
34663
34664 while (r < r_end) {
34665 duk_int_t ch1;
34666 duk_int_t ch2;
34667#ifdef DUK_USE_REGEXP_SUPPORT
34668 duk_int_t ch3;
34669#endif
34670 duk_size_t left;
34671
34672 ch1 = *r++;
34673 if (ch1 != DUK_ASC_DOLLAR) {
34674 goto repl_write;
34675 }
34676 left = r_end - r;
34677
34678 if (left <= 0) {
34679 goto repl_write;
34680 }
34681
34682 ch2 = r[0];
34683 switch ((int) ch2) {
34684 case DUK_ASC_DOLLAR: {
34685 ch1 = (1 << 8) + DUK_ASC_DOLLAR;
34686 goto repl_write;
34687 }
34688 case DUK_ASC_AMP: {
34689 DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_match);
34690 r++;
34691 continue;
34692 }
34693 case DUK_ASC_GRAVE: {
34694 tmp_sz = (duk_size_t) match_start_boff;
34695 DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input), tmp_sz);
34696 r++;
34697 continue;
34698 }
34699 case DUK_ASC_SINGLEQUOTE: {
34700 duk_uint32_t match_end_boff;
34701
34702 /* Use match charlen instead of bytelen, just in case the input and
34703 * match codepoint encodings would have different lengths.
34704 */
34705 match_end_boff = duk_heap_strcache_offset_char2byte(thr,
34706 h_input,
34707 match_start_coff + DUK_HSTRING_GET_CHARLEN(h_match));
34708
34709 tmp_sz = (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - match_end_boff);
34710 DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + match_end_boff, tmp_sz);
34711 r++;
34712 continue;
34713 }
34714 default: {
34715#ifdef DUK_USE_REGEXP_SUPPORT
34716 duk_int_t capnum, captmp, capadv;
34717 /* XXX: optional check, match_caps is zero if no regexp,
34718 * so dollar will be interpreted literally anyway.
34719 */
34720
34721 if (!is_regexp) {
34722 goto repl_write;
34723 }
34724
34725 if (!(ch2 >= DUK_ASC_0 && ch2 <= DUK_ASC_9)) {
34726 goto repl_write;
34727 }
34728 capnum = ch2 - DUK_ASC_0;
34729 capadv = 1;
34730
34731 if (left >= 2) {
34732 ch3 = r[1];
34733 if (ch3 >= DUK_ASC_0 && ch3 <= DUK_ASC_9) {
34734 captmp = capnum * 10 + (ch3 - DUK_ASC_0);
34735 if (captmp < match_caps) {
34736 capnum = captmp;
34737 capadv = 2;
34738 }
34739 }
34740 }
34741
34742 if (capnum > 0 && capnum < match_caps) {
34743 DUK_ASSERT(is_regexp != 0); /* match_caps == 0 without regexps */
34744
34745 /* regexp res_obj is at offset 4 */
34746 duk_get_prop_index(ctx, 4, (duk_uarridx_t) capnum);
34747 if (duk_is_string(ctx, -1)) {
34748 duk_hstring *h_tmp_str;
34749
34750 h_tmp_str = duk_get_hstring(ctx, -1);
34751 DUK_ASSERT(h_tmp_str != NULL);
34752
34753 DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_tmp_str);
34754 } else {
34755 /* undefined -> skip (replaced with empty) */
34756 }
34757 duk_pop(ctx);
34758 r += capadv;
34759 continue;
34760 } else {
34761 goto repl_write;
34762 }
34763#else /* DUK_USE_REGEXP_SUPPORT */
34764 goto repl_write; /* unconditionally */
34765#endif /* DUK_USE_REGEXP_SUPPORT */
34766 } /* default case */
34767 } /* switch (ch2) */
34768
34769 repl_write:
34770 /* ch1 = (r_increment << 8) + byte */
34771
34772 DUK_BW_WRITE_ENSURE_U8(thr, bw, (duk_uint8_t) (ch1 & 0xff));
34773 r += ch1 >> 8;
34774 } /* while repl */
34775 } /* if (is_repl_func) */
34776
34777 duk_pop(ctx); /* pop regexp res_obj or match string */
34778
34779#ifdef DUK_USE_REGEXP_SUPPORT
34780 if (!is_global) {
34781#else
34782 { /* unconditionally; is_global==0 */
34783#endif
34784 break;
34785 }
34786 }
34787
34788 /* trailer */
34789 tmp_sz = (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - prev_match_end_boff);
34790 DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff, tmp_sz);
34791
34792 DUK_ASSERT_TOP(ctx, 4);
34793 DUK_BW_COMPACT(thr, bw);
34794 duk_to_string(ctx, -1);
34795 return 1;
34796}
34797
34798/*
34799 * split()
34800 */
34801
34802/* XXX: very messy now, but works; clean up, remove unused variables (nomimally
34803 * used so compiler doesn't complain).
34804 */
34805
34806DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx) {
34807 duk_hthread *thr = (duk_hthread *) ctx;
34808 duk_hstring *h_input;
34809 duk_hstring *h_sep;
34810 duk_uint32_t limit;
34811 duk_uint32_t arr_idx;
34812#ifdef DUK_USE_REGEXP_SUPPORT
34813 duk_bool_t is_regexp;
34814#endif
34815 duk_bool_t matched; /* set to 1 if any match exists (needed for empty input special case) */
34816 duk_uint32_t prev_match_end_coff, prev_match_end_boff;
34817 duk_uint32_t match_start_boff, match_start_coff;
34818 duk_uint32_t match_end_boff, match_end_coff;
34819
34820 DUK_UNREF(thr);
34821
34822 h_input = duk_push_this_coercible_to_string(ctx);
34823 DUK_ASSERT(h_input != NULL);
34824
34825 duk_push_array(ctx);
34826
34827 if (duk_is_undefined(ctx, 1)) {
34828 limit = 0xffffffffUL;
34829 } else {
34830 limit = duk_to_uint32(ctx, 1);
34831 }
34832
34833 if (limit == 0) {
34834 return 1;
34835 }
34836
34837 /* If the separator is a RegExp, make a "clone" of it. The specification
34838 * algorithm calls [[Match]] directly for specific indices; we emulate this
34839 * by tweaking lastIndex and using a "force global" variant of duk_regexp_match()
34840 * which will use global-style matching even when the RegExp itself is non-global.
34841 */
34842
34843 if (duk_is_undefined(ctx, 0)) {
34844 /* The spec algorithm first does "R = ToString(separator)" before checking
34845 * whether separator is undefined. Since this is side effect free, we can
34846 * skip the ToString() here.
34847 */
34848 duk_dup(ctx, 2);
34849 duk_put_prop_index(ctx, 3, 0);
34850 return 1;
34851 } else if (duk_get_hobject_with_class(ctx, 0, DUK_HOBJECT_CLASS_REGEXP) != NULL) {
34852#ifdef DUK_USE_REGEXP_SUPPORT
34853 duk_push_hobject_bidx(ctx, DUK_BIDX_REGEXP_CONSTRUCTOR);
34854 duk_dup(ctx, 0);
34855 duk_new(ctx, 1); /* [ ... RegExp val ] -> [ ... res ] */
34856 duk_replace(ctx, 0);
34857 /* lastIndex is initialized to zero by new RegExp() */
34858 is_regexp = 1;
34859#else
34860 return DUK_RET_UNSUPPORTED_ERROR;
34861#endif
34862 } else {
34863 duk_to_string(ctx, 0);
34864#ifdef DUK_USE_REGEXP_SUPPORT
34865 is_regexp = 0;
34866#endif
34867 }
34868
34869 /* stack[0] = separator (string or regexp)
34870 * stack[1] = limit
34871 * stack[2] = input string
34872 * stack[3] = result array
34873 */
34874
34875 prev_match_end_boff = 0;
34876 prev_match_end_coff = 0;
34877 arr_idx = 0;
34878 matched = 0;
34879
34880 for (;;) {
34881 /*
34882 * The specification uses RegExp [[Match]] to attempt match at specific
34883 * offsets. We don't have such a primitive, so we use an actual RegExp
34884 * and tweak lastIndex. Since the RegExp may be non-global, we use a
34885 * special variant which forces global-like behavior for matching.
34886 */
34887
34888 DUK_ASSERT_TOP(ctx, 4);
34889
34890#ifdef DUK_USE_REGEXP_SUPPORT
34891 if (is_regexp) {
34892 duk_dup(ctx, 0);
34893 duk_dup(ctx, 2);
34894 duk_regexp_match_force_global(thr); /* [ ... regexp input ] -> [ res_obj ] */
34895 if (!duk_is_object(ctx, -1)) {
34896 duk_pop(ctx);
34897 break;
34898 }
34899 matched = 1;
34900
34901 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INDEX);
34902 DUK_ASSERT(duk_is_number(ctx, -1));
34903 match_start_coff = duk_get_int(ctx, -1);
34904 match_start_boff = duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff);
34905 duk_pop(ctx);
34906
34907 if (match_start_coff == DUK_HSTRING_GET_CHARLEN(h_input)) {
34908 /* don't allow an empty match at the end of the string */
34909 duk_pop(ctx);
34910 break;
34911 }
34912
34913 duk_get_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
34914 DUK_ASSERT(duk_is_number(ctx, -1));
34915 match_end_coff = duk_get_int(ctx, -1);
34916 match_end_boff = duk_heap_strcache_offset_char2byte(thr, h_input, match_end_coff);
34917 duk_pop(ctx);
34918
34919 /* empty match -> bump and continue */
34920 if (prev_match_end_boff == match_end_boff) {
34921 duk_push_int(ctx, match_end_coff + 1);
34922 duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
34923 duk_pop(ctx);
34924 continue;
34925 }
34926 } else {
34927#else /* DUK_USE_REGEXP_SUPPORT */
34928 { /* unconditionally */
34929#endif /* DUK_USE_REGEXP_SUPPORT */
34930 const duk_uint8_t *p_start, *p_end, *p; /* input string scan */
34931 const duk_uint8_t *q_start; /* match string */
34932 duk_size_t q_blen, q_clen;
34933
34934 p_start = DUK_HSTRING_GET_DATA(h_input);
34935 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
34936 p = p_start + prev_match_end_boff;
34937
34938 h_sep = duk_get_hstring(ctx, 0);
34939 DUK_ASSERT(h_sep != NULL);
34940 q_start = DUK_HSTRING_GET_DATA(h_sep);
34941 q_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sep);
34942 q_clen = (duk_size_t) DUK_HSTRING_GET_CHARLEN(h_sep);
34943
34944 p_end -= q_blen; /* ensure full memcmp() fits in while */
34945
34946 match_start_coff = prev_match_end_coff;
34947
34948 if (q_blen == 0) {
34949 /* Handle empty separator case: it will always match, and always
34950 * triggers the check in step 13.c.iii initially. Note that we
34951 * must skip to either end of string or start of first codepoint,
34952 * skipping over any continuation bytes!
34953 *
34954 * Don't allow an empty string to match at the end of the input.
34955 */
34956
34957 matched = 1; /* empty separator can always match */
34958
34959 match_start_coff++;
34960 p++;
34961 while (p < p_end) {
34962 if ((p[0] & 0xc0) != 0x80) {
34963 goto found;
34964 }
34965 p++;
34966 }
34967 goto not_found;
34968 }
34969
34970 DUK_ASSERT(q_blen > 0 && q_clen > 0);
34971 while (p <= p_end) {
34972 DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input));
34973 DUK_ASSERT(q_blen > 0); /* no issues with empty memcmp() */
11fdf7f2 34974 if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
7c673cae
FG
34975 /* never an empty match, so step 13.c.iii can't be triggered */
34976 goto found;
34977 }
34978
34979 /* track utf-8 non-continuation bytes */
34980 if ((p[0] & 0xc0) != 0x80) {
34981 match_start_coff++;
34982 }
34983 p++;
34984 }
34985
34986 not_found:
34987 /* not found */
34988 break;
34989
34990 found:
34991 matched = 1;
34992 match_start_boff = (duk_uint32_t) (p - p_start);
34993 match_end_coff = (duk_uint32_t) (match_start_coff + q_clen); /* constrained by string length */
34994 match_end_boff = (duk_uint32_t) (match_start_boff + q_blen); /* ditto */
34995
34996 /* empty match (may happen with empty separator) -> bump and continue */
34997 if (prev_match_end_boff == match_end_boff) {
34998 prev_match_end_boff++;
34999 prev_match_end_coff++;
35000 continue;
35001 }
35002 } /* if (is_regexp) */
35003
35004 /* stack[0] = separator (string or regexp)
35005 * stack[1] = limit
35006 * stack[2] = input string
35007 * stack[3] = result array
35008 * stack[4] = regexp res_obj (if is_regexp)
35009 */
35010
35011 DUK_DDD(DUK_DDDPRINT("split; match_start b=%ld,c=%ld, match_end b=%ld,c=%ld, prev_end b=%ld,c=%ld",
35012 (long) match_start_boff, (long) match_start_coff,
35013 (long) match_end_boff, (long) match_end_coff,
35014 (long) prev_match_end_boff, (long) prev_match_end_coff));
35015
35016 duk_push_lstring(ctx,
35017 (const char *) (DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff),
35018 (duk_size_t) (match_start_boff - prev_match_end_boff));
35019 duk_put_prop_index(ctx, 3, arr_idx);
35020 arr_idx++;
35021 if (arr_idx >= limit) {
35022 goto hit_limit;
35023 }
35024
35025#ifdef DUK_USE_REGEXP_SUPPORT
35026 if (is_regexp) {
35027 duk_size_t i, len;
35028
35029 len = duk_get_length(ctx, 4);
35030 for (i = 1; i < len; i++) {
35031 DUK_ASSERT(i <= DUK_UARRIDX_MAX); /* cannot have >4G captures */
35032 duk_get_prop_index(ctx, 4, (duk_uarridx_t) i);
35033 duk_put_prop_index(ctx, 3, arr_idx);
35034 arr_idx++;
35035 if (arr_idx >= limit) {
35036 goto hit_limit;
35037 }
35038 }
35039
35040 duk_pop(ctx);
35041 /* lastIndex already set up for next match */
35042 } else {
35043#else /* DUK_USE_REGEXP_SUPPORT */
35044 { /* unconditionally */
35045#endif /* DUK_USE_REGEXP_SUPPORT */
35046 /* no action */
35047 }
35048
35049 prev_match_end_boff = match_end_boff;
35050 prev_match_end_coff = match_end_coff;
35051 continue;
35052 } /* for */
35053
35054 /* Combined step 11 (empty string special case) and 14-15. */
35055
35056 DUK_DDD(DUK_DDDPRINT("split trailer; prev_end b=%ld,c=%ld",
35057 (long) prev_match_end_boff, (long) prev_match_end_coff));
35058
35059 if (DUK_HSTRING_GET_CHARLEN(h_input) > 0 || !matched) {
35060 /* Add trailer if:
35061 * a) non-empty input
35062 * b) empty input and no (zero size) match found (step 11)
35063 */
35064
35065 duk_push_lstring(ctx,
35066 (const char *) DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff,
35067 (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - prev_match_end_boff));
35068 duk_put_prop_index(ctx, 3, arr_idx);
35069 /* No arr_idx update or limit check */
35070 }
35071
35072 return 1;
35073
35074 hit_limit:
35075#ifdef DUK_USE_REGEXP_SUPPORT
35076 if (is_regexp) {
35077 duk_pop(ctx);
35078 }
35079#endif
35080
35081 return 1;
35082}
35083
35084/*
35085 * Various
35086 */
35087
35088#ifdef DUK_USE_REGEXP_SUPPORT
35089DUK_LOCAL void duk__to_regexp_helper(duk_context *ctx, duk_idx_t index, duk_bool_t force_new) {
35090 duk_hobject *h;
35091
35092 /* Shared helper for match() steps 3-4, search() steps 3-4. */
35093
35094 DUK_ASSERT(index >= 0);
35095
35096 if (force_new) {
35097 goto do_new;
35098 }
35099
35100 h = duk_get_hobject_with_class(ctx, index, DUK_HOBJECT_CLASS_REGEXP);
35101 if (!h) {
35102 goto do_new;
35103 }
35104 return;
35105
35106 do_new:
35107 duk_push_hobject_bidx(ctx, DUK_BIDX_REGEXP_CONSTRUCTOR);
35108 duk_dup(ctx, index);
35109 duk_new(ctx, 1); /* [ ... RegExp val ] -> [ ... res ] */
35110 duk_replace(ctx, index);
35111}
35112#endif /* DUK_USE_REGEXP_SUPPORT */
35113
35114#ifdef DUK_USE_REGEXP_SUPPORT
35115DUK_INTERNAL duk_ret_t duk_bi_string_prototype_search(duk_context *ctx) {
35116 duk_hthread *thr = (duk_hthread *) ctx;
35117
35118 /* Easiest way to implement the search required by the specification
35119 * is to do a RegExp test() with lastIndex forced to zero. To avoid
35120 * side effects on the argument, "clone" the RegExp if a RegExp was
35121 * given as input.
35122 *
35123 * The global flag of the RegExp should be ignored; setting lastIndex
35124 * to zero (which happens when "cloning" the RegExp) should have an
35125 * equivalent effect.
35126 */
35127
35128 DUK_ASSERT_TOP(ctx, 1);
35129 (void) duk_push_this_coercible_to_string(ctx); /* at index 1 */
35130 duk__to_regexp_helper(ctx, 0 /*index*/, 1 /*force_new*/);
35131
35132 /* stack[0] = regexp
35133 * stack[1] = string
35134 */
35135
35136 /* Avoid using RegExp.prototype methods, as they're writable and
35137 * configurable and may have been changed.
35138 */
35139
35140 duk_dup(ctx, 0);
35141 duk_dup(ctx, 1); /* [ ... re_obj input ] */
35142 duk_regexp_match(thr); /* -> [ ... res_obj ] */
35143
35144 if (!duk_is_object(ctx, -1)) {
35145 duk_push_int(ctx, -1);
35146 return 1;
35147 }
35148
35149 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INDEX);
35150 DUK_ASSERT(duk_is_number(ctx, -1));
35151 return 1;
35152}
35153#else /* DUK_USE_REGEXP_SUPPORT */
35154DUK_INTERNAL duk_ret_t duk_bi_string_prototype_search(duk_context *ctx) {
35155 DUK_UNREF(ctx);
35156 return DUK_RET_UNSUPPORTED_ERROR;
35157}
35158#endif /* DUK_USE_REGEXP_SUPPORT */
35159
35160#ifdef DUK_USE_REGEXP_SUPPORT
35161DUK_INTERNAL duk_ret_t duk_bi_string_prototype_match(duk_context *ctx) {
35162 duk_hthread *thr = (duk_hthread *) ctx;
35163 duk_bool_t global;
35164 duk_int_t prev_last_index;
35165 duk_int_t this_index;
35166 duk_int_t arr_idx;
35167
35168 DUK_ASSERT_TOP(ctx, 1);
35169 (void) duk_push_this_coercible_to_string(ctx);
35170 duk__to_regexp_helper(ctx, 0 /*index*/, 0 /*force_new*/);
35171 global = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_GLOBAL, NULL);
35172 DUK_ASSERT_TOP(ctx, 2);
35173
35174 /* stack[0] = regexp
35175 * stack[1] = string
35176 */
35177
35178 if (!global) {
35179 duk_regexp_match(thr); /* -> [ res_obj ] */
35180 return 1; /* return 'res_obj' */
35181 }
35182
35183 /* Global case is more complex. */
35184
35185 /* [ regexp string ] */
35186
35187 duk_push_int(ctx, 0);
35188 duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
35189 duk_push_array(ctx);
35190
35191 /* [ regexp string res_arr ] */
35192
35193 prev_last_index = 0;
35194 arr_idx = 0;
35195
35196 for (;;) {
35197 DUK_ASSERT_TOP(ctx, 3);
35198
35199 duk_dup(ctx, 0);
35200 duk_dup(ctx, 1);
35201 duk_regexp_match(thr); /* -> [ ... regexp string ] -> [ ... res_obj ] */
35202
35203 if (!duk_is_object(ctx, -1)) {
35204 duk_pop(ctx);
35205 break;
35206 }
35207
35208 duk_get_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
35209 DUK_ASSERT(duk_is_number(ctx, -1));
35210 this_index = duk_get_int(ctx, -1);
35211 duk_pop(ctx);
35212
35213 if (this_index == prev_last_index) {
35214 this_index++;
35215 duk_push_int(ctx, this_index);
35216 duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
35217 }
35218 prev_last_index = this_index;
35219
35220 duk_get_prop_index(ctx, -1, 0); /* match string */
35221 duk_put_prop_index(ctx, 2, arr_idx);
35222 arr_idx++;
35223 duk_pop(ctx); /* res_obj */
35224 }
35225
35226 if (arr_idx == 0) {
35227 duk_push_null(ctx);
35228 }
35229
35230 return 1; /* return 'res_arr' or 'null' */
35231}
35232#else /* DUK_USE_REGEXP_SUPPORT */
35233DUK_INTERNAL duk_ret_t duk_bi_string_prototype_match(duk_context *ctx) {
35234 DUK_UNREF(ctx);
35235 return DUK_RET_UNSUPPORTED_ERROR;
35236}
35237#endif /* DUK_USE_REGEXP_SUPPORT */
35238
35239DUK_INTERNAL duk_ret_t duk_bi_string_prototype_concat(duk_context *ctx) {
35240 /* duk_concat() coerces arguments with ToString() in correct order */
35241 (void) duk_push_this_coercible_to_string(ctx);
35242 duk_insert(ctx, 0); /* this is relatively expensive */
35243 duk_concat(ctx, duk_get_top(ctx));
35244 return 1;
35245}
35246
35247DUK_INTERNAL duk_ret_t duk_bi_string_prototype_trim(duk_context *ctx) {
35248 DUK_ASSERT_TOP(ctx, 0);
35249 (void) duk_push_this_coercible_to_string(ctx);
35250 duk_trim(ctx, 0);
35251 DUK_ASSERT_TOP(ctx, 1);
35252 return 1;
35253}
35254
35255DUK_INTERNAL duk_ret_t duk_bi_string_prototype_locale_compare(duk_context *ctx) {
35256 duk_hstring *h1;
35257 duk_hstring *h2;
35258 duk_size_t h1_len, h2_len, prefix_len;
35259 duk_small_int_t ret = 0;
35260 duk_small_int_t rc;
35261
35262 /* The current implementation of localeCompare() is simply a codepoint
35263 * by codepoint comparison, implemented with a simple string compare
35264 * because UTF-8 should preserve codepoint ordering (assuming valid
35265 * shortest UTF-8 encoding).
35266 *
35267 * The specification requires that the return value must be related
35268 * to the sort order: e.g. negative means that 'this' comes before
35269 * 'that' in sort order. We assume an ascending sort order.
35270 */
35271
35272 /* XXX: could share code with duk_js_ops.c, duk_js_compare_helper */
35273
35274 h1 = duk_push_this_coercible_to_string(ctx);
35275 DUK_ASSERT(h1 != NULL);
35276
35277 h2 = duk_to_hstring(ctx, 0);
35278 DUK_ASSERT(h2 != NULL);
35279
35280 h1_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1);
35281 h2_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2);
35282 prefix_len = (h1_len <= h2_len ? h1_len : h2_len);
35283
35284 /* Zero size compare not an issue with DUK_MEMCMP. */
11fdf7f2
TL
35285 rc = (duk_small_int_t) DUK_MEMCMP((const void *) DUK_HSTRING_GET_DATA(h1),
35286 (const void *) DUK_HSTRING_GET_DATA(h2),
35287 (size_t) prefix_len);
7c673cae
FG
35288
35289 if (rc < 0) {
35290 ret = -1;
35291 goto done;
35292 } else if (rc > 0) {
35293 ret = 1;
35294 goto done;
35295 }
35296
35297 /* prefix matches, lengths matter now */
35298 if (h1_len > h2_len) {
35299 ret = 1;
35300 goto done;
35301 } else if (h1_len == h2_len) {
35302 DUK_ASSERT(ret == 0);
35303 goto done;
35304 }
35305 ret = -1;
35306 goto done;
35307
35308 done:
35309 duk_push_int(ctx, (duk_int_t) ret);
35310 return 1;
35311}
7c673cae
FG
35312/*
35313 * Thread builtins
35314 */
35315
35316/* include removed: duk_internal.h */
35317
35318/*
35319 * Constructor
35320 */
35321
35322DUK_INTERNAL duk_ret_t duk_bi_thread_constructor(duk_context *ctx) {
35323 duk_hthread *new_thr;
35324 duk_hobject *func;
35325
35326 /* XXX: need a duk_require_func_or_lfunc_coerce() */
35327 if (!duk_is_callable(ctx, 0)) {
35328 return DUK_RET_TYPE_ERROR;
35329 }
35330 func = duk_require_hobject_or_lfunc_coerce(ctx, 0);
35331 DUK_ASSERT(func != NULL);
35332
35333 duk_push_thread(ctx);
35334 new_thr = (duk_hthread *) duk_get_hobject(ctx, -1);
35335 DUK_ASSERT(new_thr != NULL);
35336 new_thr->state = DUK_HTHREAD_STATE_INACTIVE;
35337
35338 /* push initial function call to new thread stack; this is
35339 * picked up by resume().
35340 */
35341 duk_push_hobject((duk_context *) new_thr, func);
35342
35343 return 1; /* return thread */
35344}
35345
35346/*
35347 * Resume a thread.
35348 *
35349 * The thread must be in resumable state, either (a) new thread which hasn't
35350 * yet started, or (b) a thread which has previously yielded. This method
35351 * must be called from an Ecmascript function.
35352 *
35353 * Args:
35354 * - thread
35355 * - value
35356 * - isError (defaults to false)
35357 *
35358 * Note: yield and resume handling is currently asymmetric.
35359 */
35360
35361DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_context *ctx) {
35362 duk_hthread *thr = (duk_hthread *) ctx;
35363 duk_hthread *thr_resume;
7c673cae
FG
35364 duk_tval *tv;
35365 duk_hobject *func;
35366 duk_hobject *caller_func;
35367 duk_small_int_t is_error;
35368
35369 DUK_DDD(DUK_DDDPRINT("Duktape.Thread.resume(): thread=%!T, value=%!T, is_error=%!T",
35370 (duk_tval *) duk_get_tval(ctx, 0),
35371 (duk_tval *) duk_get_tval(ctx, 1),
35372 (duk_tval *) duk_get_tval(ctx, 2)));
35373
35374 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
35375 DUK_ASSERT(thr->heap->curr_thread == thr);
35376
35377 thr_resume = duk_require_hthread(ctx, 0);
35378 is_error = (duk_small_int_t) duk_to_boolean(ctx, 2);
35379 duk_set_top(ctx, 2);
35380
35381 /* [ thread value ] */
35382
35383 /*
35384 * Thread state and calling context checks
35385 */
35386
35387 if (thr->callstack_top < 2) {
35388 DUK_DD(DUK_DDPRINT("resume state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.resume)"));
35389 goto state_error;
35390 }
35391 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); /* us */
35392 DUK_ASSERT(DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)));
35393 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL); /* caller */
35394
35395 caller_func = DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2);
35396 if (!DUK_HOBJECT_IS_COMPILEDFUNCTION(caller_func)) {
35397 DUK_DD(DUK_DDPRINT("resume state invalid: caller must be Ecmascript code"));
35398 goto state_error;
35399 }
35400
35401 /* Note: there is no requirement that: 'thr->callstack_preventcount == 1'
35402 * like for yield.
35403 */
35404
35405 if (thr_resume->state != DUK_HTHREAD_STATE_INACTIVE &&
35406 thr_resume->state != DUK_HTHREAD_STATE_YIELDED) {
35407 DUK_DD(DUK_DDPRINT("resume state invalid: target thread must be INACTIVE or YIELDED"));
35408 goto state_error;
35409 }
35410
35411 DUK_ASSERT(thr_resume->state == DUK_HTHREAD_STATE_INACTIVE ||
35412 thr_resume->state == DUK_HTHREAD_STATE_YIELDED);
35413
35414 /* Further state-dependent pre-checks */
35415
35416 if (thr_resume->state == DUK_HTHREAD_STATE_YIELDED) {
35417 /* no pre-checks now, assume a previous yield() has left things in
35418 * tip-top shape (longjmp handler will assert for these).
35419 */
35420 } else {
35421 DUK_ASSERT(thr_resume->state == DUK_HTHREAD_STATE_INACTIVE);
35422
35423 if ((thr_resume->callstack_top != 0) ||
35424 (thr_resume->valstack_top - thr_resume->valstack != 1)) {
35425 goto state_invalid_initial;
35426 }
35427 tv = &thr_resume->valstack_top[-1];
35428 DUK_ASSERT(tv >= thr_resume->valstack && tv < thr_resume->valstack_top);
35429 if (!DUK_TVAL_IS_OBJECT(tv)) {
35430 goto state_invalid_initial;
35431 }
35432 func = DUK_TVAL_GET_OBJECT(tv);
35433 DUK_ASSERT(func != NULL);
35434 if (!DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
35435 /* Note: cannot be a bound function either right now,
35436 * this would be easy to relax though.
35437 */
35438 goto state_invalid_initial;
35439 }
35440
35441 }
35442
35443 /*
35444 * The error object has been augmented with a traceback and other
35445 * info from its creation point -- usually another thread. The
35446 * error handler is called here right before throwing, but it also
35447 * runs in the resumer's thread. It might be nice to get a traceback
35448 * from the resumee but this is not the case now.
35449 */
35450
35451#if defined(DUK_USE_AUGMENT_ERROR_THROW)
35452 if (is_error) {
35453 DUK_ASSERT_TOP(ctx, 2); /* value (error) is at stack top */
35454 duk_err_augment_error_throw(thr); /* in resumer's context */
35455 }
35456#endif
35457
35458#ifdef DUK_USE_DEBUG
35459 if (is_error) {
35460 DUK_DDD(DUK_DDDPRINT("RESUME ERROR: thread=%!T, value=%!T",
35461 (duk_tval *) duk_get_tval(ctx, 0),
35462 (duk_tval *) duk_get_tval(ctx, 1)));
35463 } else if (thr_resume->state == DUK_HTHREAD_STATE_YIELDED) {
35464 DUK_DDD(DUK_DDDPRINT("RESUME NORMAL: thread=%!T, value=%!T",
35465 (duk_tval *) duk_get_tval(ctx, 0),
35466 (duk_tval *) duk_get_tval(ctx, 1)));
35467 } else {
35468 DUK_DDD(DUK_DDDPRINT("RESUME INITIAL: thread=%!T, value=%!T",
35469 (duk_tval *) duk_get_tval(ctx, 0),
35470 (duk_tval *) duk_get_tval(ctx, 1)));
35471 }
35472#endif
35473
35474 thr->heap->lj.type = DUK_LJ_TYPE_RESUME;
35475
35476 /* lj value2: thread */
35477 DUK_ASSERT(thr->valstack_bottom < thr->valstack_top);
11fdf7f2 35478 DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value2, &thr->valstack_bottom[0]); /* side effects */
7c673cae
FG
35479
35480 /* lj value1: value */
35481 DUK_ASSERT(thr->valstack_bottom + 1 < thr->valstack_top);
11fdf7f2
TL
35482 DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, &thr->valstack_bottom[1]); /* side effects */
35483 DUK_TVAL_CHKFAST_INPLACE(&thr->heap->lj.value1);
7c673cae
FG
35484
35485 thr->heap->lj.iserror = is_error;
35486
35487 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* call is from executor, so we know we have a jmpbuf */
35488 duk_err_longjmp(thr); /* execution resumes in bytecode executor */
35489 return 0; /* never here */
35490
35491 state_invalid_initial:
11fdf7f2 35492 DUK_ERROR_TYPE(thr, "invalid initial thread state/stack");
7c673cae
FG
35493 return 0; /* never here */
35494
35495 state_error:
11fdf7f2 35496 DUK_ERROR_TYPE(thr, "invalid state");
7c673cae
FG
35497 return 0; /* never here */
35498}
35499
35500/*
35501 * Yield the current thread.
35502 *
35503 * The thread must be in yieldable state: it must have a resumer, and there
35504 * must not be any yield-preventing calls (native calls and constructor calls,
35505 * currently) in the thread's call stack (otherwise a resume would not be
35506 * possible later). This method must be called from an Ecmascript function.
35507 *
35508 * Args:
35509 * - value
35510 * - isError (defaults to false)
35511 *
35512 * Note: yield and resume handling is currently asymmetric.
35513 */
35514
35515DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_context *ctx) {
35516 duk_hthread *thr = (duk_hthread *) ctx;
7c673cae
FG
35517 duk_hobject *caller_func;
35518 duk_small_int_t is_error;
35519
35520 DUK_DDD(DUK_DDDPRINT("Duktape.Thread.yield(): value=%!T, is_error=%!T",
35521 (duk_tval *) duk_get_tval(ctx, 0),
35522 (duk_tval *) duk_get_tval(ctx, 1)));
35523
35524 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
35525 DUK_ASSERT(thr->heap->curr_thread == thr);
35526
35527 is_error = (duk_small_int_t) duk_to_boolean(ctx, 1);
35528 duk_set_top(ctx, 1);
35529
35530 /* [ value ] */
35531
35532 /*
35533 * Thread state and calling context checks
35534 */
35535
35536 if (!thr->resumer) {
35537 DUK_DD(DUK_DDPRINT("yield state invalid: current thread must have a resumer"));
35538 goto state_error;
35539 }
35540 DUK_ASSERT(thr->resumer->state == DUK_HTHREAD_STATE_RESUMED);
35541
35542 if (thr->callstack_top < 2) {
35543 DUK_DD(DUK_DDPRINT("yield state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.yield)"));
35544 goto state_error;
35545 }
35546 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); /* us */
35547 DUK_ASSERT(DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)));
35548 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL); /* caller */
35549
35550 caller_func = DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2);
35551 if (!DUK_HOBJECT_IS_COMPILEDFUNCTION(caller_func)) {
35552 DUK_DD(DUK_DDPRINT("yield state invalid: caller must be Ecmascript code"));
35553 goto state_error;
35554 }
35555
35556 DUK_ASSERT(thr->callstack_preventcount >= 1); /* should never be zero, because we (Duktape.Thread.yield) are on the stack */
35557 if (thr->callstack_preventcount != 1) {
35558 /* Note: the only yield-preventing call is Duktape.Thread.yield(), hence check for 1, not 0 */
35559 DUK_DD(DUK_DDPRINT("yield state invalid: there must be no yield-preventing calls in current thread callstack (preventcount is %ld)",
35560 (long) thr->callstack_preventcount));
35561 goto state_error;
35562 }
35563
35564 /*
35565 * The error object has been augmented with a traceback and other
35566 * info from its creation point -- usually the current thread.
35567 * The error handler, however, is called right before throwing
35568 * and runs in the yielder's thread.
35569 */
35570
35571#if defined(DUK_USE_AUGMENT_ERROR_THROW)
35572 if (is_error) {
35573 DUK_ASSERT_TOP(ctx, 1); /* value (error) is at stack top */
35574 duk_err_augment_error_throw(thr); /* in yielder's context */
35575 }
35576#endif
35577
35578#ifdef DUK_USE_DEBUG
35579 if (is_error) {
35580 DUK_DDD(DUK_DDDPRINT("YIELD ERROR: value=%!T",
35581 (duk_tval *) duk_get_tval(ctx, 0)));
35582 } else {
35583 DUK_DDD(DUK_DDDPRINT("YIELD NORMAL: value=%!T",
35584 (duk_tval *) duk_get_tval(ctx, 0)));
35585 }
35586#endif
35587
35588 /*
35589 * Process yield
35590 *
35591 * After longjmp(), processing continues in bytecode executor longjmp
35592 * handler, which will e.g. update thr->resumer to NULL.
35593 */
35594
35595 thr->heap->lj.type = DUK_LJ_TYPE_YIELD;
35596
35597 /* lj value1: value */
35598 DUK_ASSERT(thr->valstack_bottom < thr->valstack_top);
11fdf7f2
TL
35599 DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, &thr->valstack_bottom[0]); /* side effects */
35600 DUK_TVAL_CHKFAST_INPLACE(&thr->heap->lj.value1);
7c673cae
FG
35601
35602 thr->heap->lj.iserror = is_error;
35603
35604 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* call is from executor, so we know we have a jmpbuf */
35605 duk_err_longjmp(thr); /* execution resumes in bytecode executor */
35606 return 0; /* never here */
35607
35608 state_error:
11fdf7f2 35609 DUK_ERROR_TYPE(thr, "invalid state");
7c673cae
FG
35610 return 0; /* never here */
35611}
35612
35613DUK_INTERNAL duk_ret_t duk_bi_thread_current(duk_context *ctx) {
35614 duk_push_current_thread(ctx);
35615 return 1;
35616}
7c673cae
FG
35617/*
35618 * Type error thrower, E5 Section 13.2.3.
35619 */
35620
35621/* include removed: duk_internal.h */
35622
35623DUK_INTERNAL duk_ret_t duk_bi_type_error_thrower(duk_context *ctx) {
35624 DUK_UNREF(ctx);
35625 return DUK_RET_TYPE_ERROR;
35626}
7c673cae
FG
35627/*
35628 * Fixed buffer helper useful for debugging, requires no allocation
35629 * which is critical for debugging.
35630 */
35631
35632/* include removed: duk_internal.h */
35633
35634#ifdef DUK_USE_DEBUG
35635
11fdf7f2 35636DUK_INTERNAL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffer, duk_size_t length) {
7c673cae
FG
35637 duk_size_t avail;
35638 duk_size_t copylen;
35639
35640 avail = (fb->offset >= fb->length ? (duk_size_t) 0 : (duk_size_t) (fb->length - fb->offset));
35641 if (length > avail) {
35642 copylen = avail;
35643 fb->truncated = 1;
35644 } else {
35645 copylen = length;
35646 }
35647 DUK_MEMCPY(fb->buffer + fb->offset, buffer, copylen);
35648 fb->offset += copylen;
35649}
35650
35651DUK_INTERNAL void duk_fb_put_byte(duk_fixedbuffer *fb, duk_uint8_t x) {
11fdf7f2 35652 duk_fb_put_bytes(fb, (const duk_uint8_t *) &x, 1);
7c673cae
FG
35653}
35654
35655DUK_INTERNAL void duk_fb_put_cstring(duk_fixedbuffer *fb, const char *x) {
11fdf7f2 35656 duk_fb_put_bytes(fb, (const duk_uint8_t *) x, (duk_size_t) DUK_STRLEN(x));
7c673cae
FG
35657}
35658
35659DUK_INTERNAL void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...) {
35660 duk_size_t avail;
35661 va_list ap;
35662
35663 va_start(ap, fmt);
35664 avail = (fb->offset >= fb->length ? (duk_size_t) 0 : (duk_size_t) (fb->length - fb->offset));
35665 if (avail > 0) {
35666 duk_int_t res = (duk_int_t) DUK_VSNPRINTF((char *) (fb->buffer + fb->offset), avail, fmt, ap);
35667 if (res < 0) {
35668 /* error */
35669 } else if ((duk_size_t) res >= avail) {
35670 /* (maybe) truncated */
35671 fb->offset += avail;
35672 if ((duk_size_t) res > avail) {
35673 /* actual chars dropped (not just NUL term) */
35674 fb->truncated = 1;
35675 }
35676 } else {
35677 /* normal */
35678 fb->offset += res;
35679 }
35680 }
35681 va_end(ap);
35682}
35683
35684DUK_INTERNAL void duk_fb_put_funcptr(duk_fixedbuffer *fb, duk_uint8_t *fptr, duk_size_t fptr_size) {
35685 char buf[64+1];
35686 duk_debug_format_funcptr(buf, sizeof(buf), fptr, fptr_size);
35687 buf[sizeof(buf) - 1] = (char) 0;
35688 duk_fb_put_cstring(fb, buf);
35689}
35690
35691DUK_INTERNAL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb) {
35692 return (fb->offset >= fb->length);
35693}
35694
35695#endif /* DUK_USE_DEBUG */
7c673cae
FG
35696/*
35697 * Debug dumping of duk_heap.
35698 */
35699
35700/* include removed: duk_internal.h */
35701
35702#ifdef DUK_USE_DEBUG
35703
35704#if 0 /*unused*/
35705DUK_LOCAL void duk__sanitize_snippet(char *buf, duk_size_t buf_size, duk_hstring *str) {
35706 duk_size_t i;
35707 duk_size_t nchars;
35708 duk_size_t maxchars;
35709 duk_uint8_t *data;
35710
35711 DUK_MEMZERO(buf, buf_size);
35712
35713 maxchars = (duk_size_t) (buf_size - 1);
35714 data = DUK_HSTRING_GET_DATA(str);
35715 nchars = ((duk_size_t) str->blen < maxchars ? (duk_size_t) str->blen : maxchars);
35716 for (i = 0; i < nchars; i++) {
35717 duk_small_int_t c = (duk_small_int_t) data[i];
35718 if (c < 0x20 || c > 0x7e) {
35719 c = '.';
35720 }
35721 buf[i] = (char) c;
35722 }
35723}
35724#endif
35725
35726#if 0
35727DUK_LOCAL const char *duk__get_heap_type_string(duk_heaphdr *hdr) {
35728 switch (DUK_HEAPHDR_GET_TYPE(hdr)) {
35729 case DUK_HTYPE_STRING:
35730 return "string";
35731 case DUK_HTYPE_OBJECT:
35732 return "object";
35733 case DUK_HTYPE_BUFFER:
35734 return "buffer";
35735 default:
35736 return "???";
35737 }
35738}
35739#endif
35740
35741#if 0
35742DUK_LOCAL void duk__dump_indented(duk_heaphdr *obj, int index) {
35743 DUK_UNREF(obj);
35744 DUK_UNREF(index);
35745 DUK_UNREF(duk__get_heap_type_string);
35746
35747#ifdef DUK_USE_REFERENCE_COUNTING
35748 DUK_D(DUK_DPRINT(" [%ld]: %p %s (flags: 0x%08lx, ref: %ld) -> %!O",
35749 (long) index,
35750 (void *) obj,
35751 (const char *) duk__get_heap_type_string(obj),
35752 (unsigned long) DUK_HEAPHDR_GET_FLAGS(obj),
35753 (long) DUK_HEAPHDR_GET_REFCOUNT(obj),
35754 (duk_heaphdr *) obj));
35755#else
35756 DUK_D(DUK_DPRINT(" [%ld]: %p %s (flags: 0x%08lx) -> %!O",
35757 (long) index,
35758 (void *) obj,
35759 (const char *) duk__get_heap_type_string(obj),
35760 (unsigned long) DUK_HEAPHDR_GET_FLAGS(obj),
35761 (duk_heaphdr *) obj));
35762#endif
35763}
35764#endif
35765
35766#if 0 /*unused*/
35767DUK_LOCAL void duk__dump_heaphdr_list(duk_heap *heap, duk_heaphdr *root, const char *name) {
35768 duk_int_t count;
35769 duk_heaphdr *curr;
35770
35771 DUK_UNREF(heap);
35772 DUK_UNREF(name);
35773
35774 count = 0;
35775 curr = root;
35776 while (curr) {
35777 count++;
35778 curr = DUK_HEAPHDR_GET_NEXT(curr);
35779 }
35780
35781 DUK_D(DUK_DPRINT("%s, %ld objects", (const char *) name, (long) count));
35782
35783 count = 0;
35784 curr = root;
35785 while (curr) {
35786 count++;
35787 duk__dump_indented(curr, count);
35788 curr = DUK_HEAPHDR_GET_NEXT(curr);
35789 }
35790}
35791#endif
35792
35793#if 0 /*unused*/
35794DUK_LOCAL void duk__dump_stringtable(duk_heap *heap) {
35795 duk_uint_fast32_t i;
35796 char buf[64+1];
35797
35798 DUK_D(DUK_DPRINT("stringtable %p, used %ld, size %ld, load %ld%%",
35799 (void *) heap->strtable,
35800 (long) heap->st_used,
35801 (long) heap->st_size,
35802 (long) (((double) heap->st_used) / ((double) heap->st_size) * 100.0)));
35803
35804 for (i = 0; i < (duk_uint_fast32_t) heap->st_size; i++) {
35805 duk_hstring *e = heap->strtable[i];
35806
35807 if (!e) {
35808 DUK_D(DUK_DPRINT(" [%ld]: NULL", (long) i));
35809 } else if (e == DUK_STRTAB_DELETED_MARKER(heap)) {
35810 DUK_D(DUK_DPRINT(" [%ld]: DELETED", (long) i));
35811 } else {
35812 duk__sanitize_snippet(buf, sizeof(buf), e);
35813
35814#ifdef DUK_USE_REFERENCE_COUNTING
35815 DUK_D(DUK_DPRINT(" [%ld]: %p (flags: 0x%08lx, ref: %ld) '%s', strhash=0x%08lx, blen=%ld, clen=%ld, "
35816 "arridx=%ld, internal=%ld, reserved_word=%ld, strict_reserved_word=%ld, eval_or_arguments=%ld",
35817 (long) i,
35818 (void *) e,
35819 (unsigned long) DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) e),
35820 (long) DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) e),
35821 (const char *) buf,
35822 (unsigned long) e->hash,
35823 (long) e->blen,
35824 (long) e->clen,
35825 (long) (DUK_HSTRING_HAS_ARRIDX(e) ? 1 : 0),
35826 (long) (DUK_HSTRING_HAS_INTERNAL(e) ? 1 : 0),
35827 (long) (DUK_HSTRING_HAS_RESERVED_WORD(e) ? 1 : 0),
35828 (long) (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(e) ? 1 : 0),
35829 (long) (DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(e) ? 1 : 0)));
35830#else
35831 DUK_D(DUK_DPRINT(" [%ld]: %p (flags: 0x%08lx) '%s', strhash=0x%08lx, blen=%ld, clen=%ld, "
35832 "arridx=%ld, internal=%ld, reserved_word=%ld, strict_reserved_word=%ld, eval_or_arguments=%ld",
35833 (long) i,
35834 (void *) e,
35835 (unsigned long) DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) e),
35836 (const char *) buf,
35837 (long) e->hash,
35838 (long) e->blen,
35839 (long) e->clen,
35840 (long) (DUK_HSTRING_HAS_ARRIDX(e) ? 1 : 0),
35841 (long) (DUK_HSTRING_HAS_INTERNAL(e) ? 1 : 0),
35842 (long) (DUK_HSTRING_HAS_RESERVED_WORD(e) ? 1 : 0),
35843 (long) (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(e) ? 1 : 0),
35844 (long) (DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(e) ? 1 : 0)));
35845#endif
35846 }
35847 }
35848}
35849#endif
35850
35851#if 0 /*unused*/
35852DUK_LOCAL void duk__dump_strcache(duk_heap *heap) {
35853 duk_uint_fast32_t i;
35854 char buf[64+1];
35855
35856 DUK_D(DUK_DPRINT("stringcache"));
35857
35858 for (i = 0; i < (duk_uint_fast32_t) DUK_HEAP_STRCACHE_SIZE; i++) {
35859 duk_strcache *c = &heap->strcache[i];
35860 if (!c->h) {
35861 DUK_D(DUK_DPRINT(" [%ld]: bidx=%ld, cidx=%ld, str=NULL",
35862 (long) i, (long) c->bidx, (long) c->cidx));
35863 } else {
35864 duk__sanitize_snippet(buf, sizeof(buf), c->h);
35865 DUK_D(DUK_DPRINT(" [%ld]: bidx=%ld cidx=%ld str=%s",
35866 (long) i, (long) c->bidx, (long) c->cidx, (const char *) buf));
35867 }
35868 }
35869}
35870#endif
35871
35872#if 0 /*unused*/
35873DUK_INTERNAL void duk_debug_dump_heap(duk_heap *heap) {
35874 char buf[64+1];
35875
35876 DUK_D(DUK_DPRINT("=== heap %p ===", (void *) heap));
35877 DUK_D(DUK_DPRINT(" flags: 0x%08lx", (unsigned long) heap->flags));
35878
35879 /* Note: there is no standard formatter for function pointers */
35880#ifdef DUK_USE_GCC_PRAGMAS
35881#pragma GCC diagnostic push
35882#pragma GCC diagnostic ignored "-pedantic"
35883#endif
35884 duk_debug_format_funcptr(buf, sizeof(buf), (duk_uint8_t *) &heap->alloc_func, sizeof(heap->alloc_func));
35885 DUK_D(DUK_DPRINT(" alloc_func: %s", (const char *) buf));
35886 duk_debug_format_funcptr(buf, sizeof(buf), (duk_uint8_t *) &heap->realloc_func, sizeof(heap->realloc_func));
35887 DUK_D(DUK_DPRINT(" realloc_func: %s", (const char *) buf));
35888 duk_debug_format_funcptr(buf, sizeof(buf), (duk_uint8_t *) &heap->free_func, sizeof(heap->free_func));
35889 DUK_D(DUK_DPRINT(" free_func: %s", (const char *) buf));
35890 duk_debug_format_funcptr(buf, sizeof(buf), (duk_uint8_t *) &heap->fatal_func, sizeof(heap->fatal_func));
35891 DUK_D(DUK_DPRINT(" fatal_func: %s", (const char *) buf));
35892#ifdef DUK_USE_GCC_PRAGMAS
35893#pragma GCC diagnostic pop
35894#endif
35895
35896 DUK_D(DUK_DPRINT(" heap_udata: %p", (void *) heap->heap_udata));
35897
35898#ifdef DUK_USE_MARK_AND_SWEEP
35899#ifdef DUK_USE_VOLUNTARY_GC
35900 DUK_D(DUK_DPRINT(" mark-and-sweep trig counter: %ld", (long) heap->mark_and_sweep_trigger_counter));
35901#endif
35902 DUK_D(DUK_DPRINT(" mark-and-sweep rec depth: %ld", (long) heap->mark_and_sweep_recursion_depth));
35903 DUK_D(DUK_DPRINT(" mark-and-sweep base flags: 0x%08lx", (unsigned long) heap->mark_and_sweep_base_flags));
35904#endif
35905
35906 DUK_D(DUK_DPRINT(" lj.jmpbuf_ptr: %p", (void *) heap->lj.jmpbuf_ptr));
35907 DUK_D(DUK_DPRINT(" lj.type: %ld", (long) heap->lj.type));
35908 DUK_D(DUK_DPRINT(" lj.value1: %!T", (duk_tval *) &heap->lj.value1));
35909 DUK_D(DUK_DPRINT(" lj.value2: %!T", (duk_tval *) &heap->lj.value2));
35910 DUK_D(DUK_DPRINT(" lj.iserror: %ld", (long) heap->lj.iserror));
35911
35912 DUK_D(DUK_DPRINT(" handling_error: %ld", (long) heap->handling_error));
35913
35914 DUK_D(DUK_DPRINT(" heap_thread: %!@O", (duk_heaphdr *) heap->heap_thread));
35915 DUK_D(DUK_DPRINT(" curr_thread: %!@O", (duk_heaphdr *) heap->curr_thread));
35916 DUK_D(DUK_DPRINT(" heap_object: %!@O", (duk_heaphdr *) heap->heap_object));
35917
35918 DUK_D(DUK_DPRINT(" call_recursion_depth: %ld", (long) heap->call_recursion_depth));
35919 DUK_D(DUK_DPRINT(" call_recursion_limit: %ld", (long) heap->call_recursion_limit));
35920
35921 DUK_D(DUK_DPRINT(" hash_seed: 0x%08lx", (unsigned long) heap->hash_seed));
35922 DUK_D(DUK_DPRINT(" rnd_state: 0x%08lx", (unsigned long) heap->rnd_state));
35923
35924 duk__dump_strcache(heap);
35925
35926 duk__dump_heaphdr_list(heap, heap->heap_allocated, "heap allocated");
35927
35928#ifdef DUK_USE_REFERENCE_COUNTING
35929 duk__dump_heaphdr_list(heap, heap->refzero_list, "refcounting refzero list");
35930#endif
35931
35932#ifdef DUK_USE_MARK_AND_SWEEP
35933 duk__dump_heaphdr_list(heap, heap->finalize_list, "mark-and-sweep finalize list");
35934#endif
35935
35936 duk__dump_stringtable(heap);
35937
35938 /* heap->strs: not worth dumping */
35939}
35940#endif
35941
35942#endif /* DUK_USE_DEBUG */
7c673cae
FG
35943/*
35944 * Custom formatter for debug printing, allowing Duktape specific data
35945 * structures (such as tagged values and heap objects) to be printed with
35946 * a nice format string. Because debug printing should not affect execution
35947 * state, formatting here must be independent of execution (see implications
35948 * below) and must not allocate memory.
35949 *
35950 * Custom format tags begin with a '%!' to safely distinguish them from
35951 * standard format tags. The following conversions are supported:
35952 *
35953 * %!T tagged value (duk_tval *)
35954 * %!O heap object (duk_heaphdr *)
35955 * %!I decoded bytecode instruction
35956 * %!C bytecode instruction opcode name (arg is long)
35957 *
35958 * Everything is serialized in a JSON-like manner. The default depth is one
35959 * level, internal prototype is not followed, and internal properties are not
35960 * serialized. The following modifiers change this behavior:
35961 *
35962 * @ print pointers
35963 * # print binary representations (where applicable)
35964 * d deep traversal of own properties (not prototype)
35965 * p follow prototype chain (useless without 'd')
35966 * i include internal properties (other than prototype)
35967 * x hexdump buffers
35968 * h heavy formatting
35969 *
35970 * For instance, the following serializes objects recursively, but does not
35971 * follow the prototype chain nor print internal properties: "%!dO".
35972 *
35973 * Notes:
35974 *
35975 * * Standard snprintf return value semantics seem to vary. This
35976 * implementation returns the number of bytes it actually wrote
35977 * (excluding the null terminator). If retval == buffer size,
35978 * output was truncated (except for corner cases).
35979 *
35980 * * Output format is intentionally different from Ecmascript
35981 * formatting requirements, as formatting here serves debugging
35982 * of internals.
35983 *
35984 * * Depth checking (and updating) is done in each type printer
35985 * separately, to allow them to call each other freely.
35986 *
35987 * * Some pathological structures might take ages to print (e.g.
35988 * self recursion with 100 properties pointing to the object
35989 * itself). To guard against these, each printer also checks
35990 * whether the output buffer is full; if so, early exit.
35991 *
35992 * * Reference loops are detected using a loop stack.
35993 */
35994
35995/* include removed: duk_internal.h */
35996
35997#ifdef DUK_USE_DEBUG
35998
35999#include <stdio.h>
36000#include <stdarg.h>
36001#include <string.h>
36002
36003/* list of conversion specifiers that terminate a format tag;
36004 * this is unfortunately guesswork.
36005 */
36006#define DUK__ALLOWED_STANDARD_SPECIFIERS "diouxXeEfFgGaAcsCSpnm"
36007
36008/* maximum length of standard format tag that we support */
36009#define DUK__MAX_FORMAT_TAG_LENGTH 32
36010
36011/* heapobj recursion depth when deep printing is selected */
36012#define DUK__DEEP_DEPTH_LIMIT 8
36013
36014/* maximum recursion depth for loop detection stacks */
36015#define DUK__LOOP_STACK_DEPTH 256
36016
36017/* must match bytecode defines now; build autogenerate? */
36018DUK_LOCAL const char *duk__bc_optab[64] = {
36019 "LDREG", "STREG", "LDCONST", "LDINT", "LDINTX", "MPUTOBJ", "MPUTOBJI", "MPUTARR", "MPUTARRI", "NEW",
36020 "NEWI", "REGEXP", "CSREG", "CSREGI", "GETVAR", "PUTVAR", "DECLVAR", "DELVAR", "CSVAR", "CSVARI",
36021 "CLOSURE", "GETPROP", "PUTPROP", "DELPROP", "CSPROP", "CSPROPI", "ADD", "SUB", "MUL", "DIV",
36022 "MOD", "BAND", "BOR", "BXOR", "BASL", "BLSR", "BASR", "EQ", "NEQ", "SEQ",
36023 "SNEQ", "GT", "GE", "LT", "LE", "IF", "JUMP", "RETURN", "CALL", "CALLI",
36024 "TRYCATCH", "EXTRA", "PREINCR", "PREDECR", "POSTINCR", "POSTDECR", "PREINCV", "PREDECV", "POSTINCV", "POSTDECV",
36025 "PREINCP", "PREDECP", "POSTINCP", "POSTDECP"
36026};
36027
36028DUK_LOCAL const char *duk__bc_extraoptab[256] = {
36029 "NOP", "INVALID", "LDTHIS", "LDUNDEF", "LDNULL", "LDTRUE", "LDFALSE", "NEWOBJ", "NEWARR", "SETALEN",
36030 "TYPEOF", "TYPEOFID", "INITENUM", "NEXTENUM", "INITSET", "INITSETI", "INITGET", "INITGETI", "ENDTRY", "ENDCATCH",
36031 "ENDFIN", "THROW", "INVLHS", "UNM", "UNP", "DEBUGGER", "BREAK", "CONTINUE", "BNOT", "LNOT",
36032 "INSTOF", "IN", "LABEL", "ENDLABEL", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36033 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36034
36035 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36036 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36037 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36038 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36039 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36040
36041 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36042 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36043 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36044 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36045 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36046
36047 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36048 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36049 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36050 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36051 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36052
36053 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36054 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36055 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36056 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36057 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
36058
36059 "XXX", "XXX", "XXX", "XXX", "XXX", "XXX"
36060};
36061
36062typedef struct duk__dprint_state duk__dprint_state;
36063struct duk__dprint_state {
36064 duk_fixedbuffer *fb;
36065
36066 /* loop_stack_index could be perhaps be replaced by 'depth', but it's nice
36067 * to not couple these two mechanisms unnecessarily.
36068 */
36069 duk_hobject *loop_stack[DUK__LOOP_STACK_DEPTH];
36070 duk_int_t loop_stack_index;
36071 duk_int_t loop_stack_limit;
36072
36073 duk_int_t depth;
36074 duk_int_t depth_limit;
36075
36076 duk_bool_t pointer;
36077 duk_bool_t heavy;
36078 duk_bool_t binary;
36079 duk_bool_t follow_proto;
36080 duk_bool_t internal;
36081 duk_bool_t hexdump;
36082};
36083
36084/* helpers */
36085DUK_LOCAL_DECL void duk__print_hstring(duk__dprint_state *st, duk_hstring *k, duk_bool_t quotes);
36086DUK_LOCAL_DECL void duk__print_hobject(duk__dprint_state *st, duk_hobject *h);
36087DUK_LOCAL_DECL void duk__print_hbuffer(duk__dprint_state *st, duk_hbuffer *h);
36088DUK_LOCAL_DECL void duk__print_tval(duk__dprint_state *st, duk_tval *tv);
36089DUK_LOCAL_DECL void duk__print_instr(duk__dprint_state *st, duk_instr_t ins);
36090DUK_LOCAL_DECL void duk__print_heaphdr(duk__dprint_state *st, duk_heaphdr *h);
36091DUK_LOCAL_DECL void duk__print_shared_heaphdr(duk__dprint_state *st, duk_heaphdr *h);
36092DUK_LOCAL_DECL void duk__print_shared_heaphdr_string(duk__dprint_state *st, duk_heaphdr_string *h);
36093
36094DUK_LOCAL void duk__print_shared_heaphdr(duk__dprint_state *st, duk_heaphdr *h) {
36095 duk_fixedbuffer *fb = st->fb;
36096
36097 if (st->heavy) {
36098 duk_fb_sprintf(fb, "(%p)", (void *) h);
36099 }
36100
36101 if (!h) {
36102 return;
36103 }
36104
36105 if (st->binary) {
36106 duk_size_t i;
36107 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LBRACKET);
36108 for (i = 0; i < (duk_size_t) sizeof(*h); i++) {
36109 duk_fb_sprintf(fb, "%02lx", (unsigned long) ((duk_uint8_t *)h)[i]);
36110 }
36111 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RBRACKET);
36112 }
36113
36114#ifdef DUK_USE_REFERENCE_COUNTING /* currently implicitly also DUK_USE_DOUBLE_LINKED_HEAP */
36115 if (st->heavy) {
36116 duk_fb_sprintf(fb, "[h_next=%p,h_prev=%p,h_refcount=%lu,h_flags=%08lx,type=%ld,"
36117 "reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]",
36118 (void *) DUK_HEAPHDR_GET_NEXT(NULL, h),
36119 (void *) DUK_HEAPHDR_GET_PREV(NULL, h),
36120 (unsigned long) DUK_HEAPHDR_GET_REFCOUNT(h),
36121 (unsigned long) DUK_HEAPHDR_GET_FLAGS(h),
36122 (long) DUK_HEAPHDR_GET_TYPE(h),
36123 (long) (DUK_HEAPHDR_HAS_REACHABLE(h) ? 1 : 0),
36124 (long) (DUK_HEAPHDR_HAS_TEMPROOT(h) ? 1 : 0),
36125 (long) (DUK_HEAPHDR_HAS_FINALIZABLE(h) ? 1 : 0),
36126 (long) (DUK_HEAPHDR_HAS_FINALIZED(h) ? 1 : 0));
36127 }
36128#else
36129 if (st->heavy) {
36130 duk_fb_sprintf(fb, "[h_next=%p,h_flags=%08lx,type=%ld,reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]",
36131 (void *) DUK_HEAPHDR_GET_NEXT(NULL, h),
36132 (unsigned long) DUK_HEAPHDR_GET_FLAGS(h),
36133 (long) DUK_HEAPHDR_GET_TYPE(h),
36134 (long) (DUK_HEAPHDR_HAS_REACHABLE(h) ? 1 : 0),
36135 (long) (DUK_HEAPHDR_HAS_TEMPROOT(h) ? 1 : 0),
36136 (long) (DUK_HEAPHDR_HAS_FINALIZABLE(h) ? 1 : 0),
36137 (long) (DUK_HEAPHDR_HAS_FINALIZED(h) ? 1 : 0));
36138 }
36139#endif
36140}
36141
36142DUK_LOCAL void duk__print_shared_heaphdr_string(duk__dprint_state *st, duk_heaphdr_string *h) {
36143 duk_fixedbuffer *fb = st->fb;
36144
36145 if (st->heavy) {
36146 duk_fb_sprintf(fb, "(%p)", (void *) h);
36147 }
36148
36149 if (!h) {
36150 return;
36151 }
36152
36153 if (st->binary) {
36154 duk_size_t i;
36155 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LBRACKET);
36156 for (i = 0; i < (duk_size_t) sizeof(*h); i++) {
36157 duk_fb_sprintf(fb, "%02lx", (unsigned long) ((duk_uint8_t *)h)[i]);
36158 }
36159 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RBRACKET);
36160 }
36161
36162#ifdef DUK_USE_REFERENCE_COUNTING
36163 if (st->heavy) {
36164 duk_fb_sprintf(fb, "[h_refcount=%lu,h_flags=%08lx,type=%ld,reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]",
36165 (unsigned long) DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h),
36166 (unsigned long) DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) h),
36167 (long) DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h),
36168 (long) (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h) ? 1 : 0),
36169 (long) (DUK_HEAPHDR_HAS_TEMPROOT((duk_heaphdr *) h) ? 1 : 0),
36170 (long) (DUK_HEAPHDR_HAS_FINALIZABLE((duk_heaphdr *) h) ? 1 : 0),
36171 (long) (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h) ? 1 : 0));
36172 }
36173#else
36174 if (st->heavy) {
36175 duk_fb_sprintf(fb, "[h_flags=%08lx,type=%ld,reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]",
36176 (unsigned long) DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) h),
36177 (long) DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h),
36178 (long) (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h) ? 1 : 0),
36179 (long) (DUK_HEAPHDR_HAS_TEMPROOT((duk_heaphdr *) h) ? 1 : 0),
36180 (long) (DUK_HEAPHDR_HAS_FINALIZABLE((duk_heaphdr *) h) ? 1 : 0),
36181 (long) (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h) ? 1 : 0));
36182 }
36183#endif
36184}
36185
36186DUK_LOCAL void duk__print_hstring(duk__dprint_state *st, duk_hstring *h, duk_bool_t quotes) {
36187 duk_fixedbuffer *fb = st->fb;
36188 const duk_uint8_t *p;
36189 const duk_uint8_t *p_end;
36190
36191 /* terminal type: no depth check */
36192
36193 if (duk_fb_is_full(fb)) {
36194 return;
36195 }
36196
36197 duk__print_shared_heaphdr_string(st, &h->hdr);
36198
36199 if (!h) {
36200 duk_fb_put_cstring(fb, "NULL");
36201 return;
36202 }
36203
36204 p = DUK_HSTRING_GET_DATA(h);
36205 p_end = p + DUK_HSTRING_GET_BYTELEN(h);
36206
36207 if (p_end > p && p[0] == DUK_ASC_UNDERSCORE) {
36208 /* if property key begins with underscore, encode it with
36209 * forced quotes (e.g. "_Foo") to distinguish it from encoded
36210 * internal properties (e.g. \xffBar -> _Bar).
36211 */
36212 quotes = 1;
36213 }
36214
36215 if (quotes) {
36216 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_DOUBLEQUOTE);
36217 }
36218 while (p < p_end) {
36219 duk_uint8_t ch = *p++;
36220
36221 /* two special escapes: '\' and '"', other printables as is */
36222 if (ch == '\\') {
36223 duk_fb_sprintf(fb, "\\\\");
36224 } else if (ch == '"') {
36225 duk_fb_sprintf(fb, "\\\"");
36226 } else if (ch >= 0x20 && ch <= 0x7e) {
36227 duk_fb_put_byte(fb, ch);
36228 } else if (ch == 0xff && !quotes) {
36229 /* encode \xffBar as _Bar if no quotes are applied, this is for
36230 * readable internal keys.
36231 */
36232 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_UNDERSCORE);
36233 } else {
36234 duk_fb_sprintf(fb, "\\x%02lx", (unsigned long) ch);
36235 }
36236 }
36237 if (quotes) {
36238 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_DOUBLEQUOTE);
36239 }
36240#ifdef DUK_USE_REFERENCE_COUNTING
36241 /* XXX: limit to quoted strings only, to save keys from being cluttered? */
36242 duk_fb_sprintf(fb, "/%lu", (unsigned long) DUK_HEAPHDR_GET_REFCOUNT(&h->hdr));
36243#endif
36244}
36245
36246#ifdef DUK__COMMA
36247#undef DUK__COMMA
36248#endif
36249#define DUK__COMMA() do { \
36250 if (first) { \
36251 first = 0; \
36252 } else { \
36253 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_COMMA); \
36254 } \
36255 } while (0)
36256
36257DUK_LOCAL void duk__print_hobject(duk__dprint_state *st, duk_hobject *h) {
36258 duk_fixedbuffer *fb = st->fb;
36259 duk_uint_fast32_t i;
36260 duk_tval *tv;
36261 duk_hstring *key;
36262 duk_bool_t first = 1;
36263 const char *brace1 = "{";
36264 const char *brace2 = "}";
36265 duk_bool_t pushed_loopstack = 0;
36266
36267 if (duk_fb_is_full(fb)) {
36268 return;
36269 }
36270
36271 duk__print_shared_heaphdr(st, &h->hdr);
36272
36273 if (h && DUK_HOBJECT_HAS_ARRAY_PART(h)) {
36274 brace1 = "[";
36275 brace2 = "]";
36276 }
36277
36278 if (!h) {
36279 duk_fb_put_cstring(fb, "NULL");
36280 goto finished;
36281 }
36282
36283 if (st->depth >= st->depth_limit) {
36284 if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
36285 duk_fb_sprintf(fb, "%sobject/compiledfunction %p%s", (const char *) brace1, (void *) h, (const char *) brace2);
36286 } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
36287 duk_fb_sprintf(fb, "%sobject/nativefunction %p%s", (const char *) brace1, (void *) h, (const char *) brace2);
36288 } else if (DUK_HOBJECT_IS_THREAD(h)) {
36289 duk_fb_sprintf(fb, "%sobject/thread %p%s", (const char *) brace1, (void *) h, (const char *) brace2);
36290 } else {
36291 duk_fb_sprintf(fb, "%sobject %p%s", (const char *) brace1, (void *) h, (const char *) brace2); /* may be NULL */
36292 }
36293 return;
36294 }
36295
36296 for (i = 0; i < (duk_uint_fast32_t) st->loop_stack_index; i++) {
36297 if (st->loop_stack[i] == h) {
36298 duk_fb_sprintf(fb, "%sLOOP:%p%s", (const char *) brace1, (void *) h, (const char *) brace2);
36299 return;
36300 }
36301 }
36302
36303 /* after this, return paths should 'goto finished' for decrement */
36304 st->depth++;
36305
36306 if (st->loop_stack_index >= st->loop_stack_limit) {
36307 duk_fb_sprintf(fb, "%sOUT-OF-LOOP-STACK%s", (const char *) brace1, (const char *) brace2);
36308 goto finished;
36309 }
36310 st->loop_stack[st->loop_stack_index++] = h;
36311 pushed_loopstack = 1;
36312
36313 /*
36314 * Notation: double underscore used for internal properties which are not
36315 * stored in the property allocation (e.g. '__valstack').
36316 */
36317
36318 duk_fb_put_cstring(fb, brace1);
36319
36320 if (DUK_HOBJECT_GET_PROPS(NULL, h)) {
36321 duk_uint32_t a_limit;
36322
36323 a_limit = DUK_HOBJECT_GET_ASIZE(h);
36324 if (st->internal) {
36325 /* dump all allocated entries, unused entries print as 'unused',
36326 * note that these may extend beyond current 'length' and look
36327 * a bit funny.
36328 */
36329 } else {
36330 /* leave out trailing 'unused' elements */
36331 while (a_limit > 0) {
36332 tv = DUK_HOBJECT_A_GET_VALUE_PTR(NULL, h, a_limit - 1);
11fdf7f2 36333 if (!DUK_TVAL_IS_UNUSED(tv)) {
7c673cae
FG
36334 break;
36335 }
36336 a_limit--;
36337 }
36338 }
36339
36340 for (i = 0; i < a_limit; i++) {
36341 tv = DUK_HOBJECT_A_GET_VALUE_PTR(NULL, h, i);
36342 DUK__COMMA();
36343 duk__print_tval(st, tv);
36344 }
36345 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(h); i++) {
36346 key = DUK_HOBJECT_E_GET_KEY(NULL, h, i);
36347 if (!key) {
36348 continue;
36349 }
36350 if (!st->internal &&
36351 DUK_HSTRING_GET_BYTELEN(key) > 0 &&
36352 DUK_HSTRING_GET_DATA(key)[0] == 0xff) {
36353 /* XXX: use DUK_HSTRING_FLAG_INTERNAL? */
36354 continue;
36355 }
36356 DUK__COMMA();
36357 duk__print_hstring(st, key, 0);
36358 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_COLON);
36359 if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(NULL, h, i)) {
36360 duk_fb_sprintf(fb, "[get:%p,set:%p]",
36361 (void *) DUK_HOBJECT_E_GET_VALUE(NULL, h, i).a.get,
36362 (void *) DUK_HOBJECT_E_GET_VALUE(NULL, h, i).a.set);
36363 } else {
36364 tv = &DUK_HOBJECT_E_GET_VALUE(NULL, h, i).v;
36365 duk__print_tval(st, tv);
36366 }
36367 if (st->heavy) {
36368 duk_fb_sprintf(fb, "<%02lx>", (unsigned long) DUK_HOBJECT_E_GET_FLAGS(NULL, h, i));
36369 }
36370 }
36371 }
36372 if (st->internal) {
36373 if (DUK_HOBJECT_HAS_EXTENSIBLE(h)) {
36374 DUK__COMMA(); duk_fb_sprintf(fb, "__extensible:true");
36375 } else {
36376 ;
36377 }
36378 if (DUK_HOBJECT_HAS_CONSTRUCTABLE(h)) {
36379 DUK__COMMA(); duk_fb_sprintf(fb, "__constructable:true");
36380 } else {
36381 ;
36382 }
36383 if (DUK_HOBJECT_HAS_BOUND(h)) {
36384 DUK__COMMA(); duk_fb_sprintf(fb, "__bound:true");
36385 } else {
36386 ;
36387 }
36388 if (DUK_HOBJECT_HAS_COMPILEDFUNCTION(h)) {
36389 DUK__COMMA(); duk_fb_sprintf(fb, "__compiledfunction:true");
36390 } else {
36391 ;
36392 }
36393 if (DUK_HOBJECT_HAS_NATIVEFUNCTION(h)) {
36394 DUK__COMMA(); duk_fb_sprintf(fb, "__nativefunction:true");
36395 } else {
36396 ;
36397 }
36398 if (DUK_HOBJECT_HAS_THREAD(h)) {
36399 DUK__COMMA(); duk_fb_sprintf(fb, "__thread:true");
36400 } else {
36401 ;
36402 }
36403 if (DUK_HOBJECT_HAS_ARRAY_PART(h)) {
36404 DUK__COMMA(); duk_fb_sprintf(fb, "__array_part:true");
36405 } else {
36406 ;
36407 }
36408 if (DUK_HOBJECT_HAS_STRICT(h)) {
36409 DUK__COMMA(); duk_fb_sprintf(fb, "__strict:true");
36410 } else {
36411 ;
36412 }
36413 if (DUK_HOBJECT_HAS_NEWENV(h)) {
36414 DUK__COMMA(); duk_fb_sprintf(fb, "__newenv:true");
36415 } else {
36416 ;
36417 }
36418 if (DUK_HOBJECT_HAS_NAMEBINDING(h)) {
36419 DUK__COMMA(); duk_fb_sprintf(fb, "__namebinding:true");
36420 } else {
36421 ;
36422 }
36423 if (DUK_HOBJECT_HAS_CREATEARGS(h)) {
36424 DUK__COMMA(); duk_fb_sprintf(fb, "__createargs:true");
36425 } else {
36426 ;
36427 }
36428 if (DUK_HOBJECT_HAS_ENVRECCLOSED(h)) {
36429 DUK__COMMA(); duk_fb_sprintf(fb, "__envrecclosed:true");
36430 } else {
36431 ;
36432 }
36433 if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)) {
11fdf7f2 36434 DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_array:true");
7c673cae
FG
36435 } else {
36436 ;
36437 }
36438 if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(h)) {
11fdf7f2 36439 DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_stringobj:true");
7c673cae
FG
36440 } else {
36441 ;
36442 }
36443 if (DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h)) {
11fdf7f2 36444 DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_arguments:true");
7c673cae
FG
36445 } else {
36446 ;
36447 }
36448 if (DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(h)) {
11fdf7f2 36449 DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_dukfunc:true");
7c673cae
FG
36450 } else {
36451 ;
36452 }
36453 if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
11fdf7f2 36454 DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_bufferobj:true");
7c673cae
FG
36455 } else {
36456 ;
36457 }
36458 if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h)) {
11fdf7f2 36459 DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_proxyobj:true");
7c673cae
FG
36460 } else {
36461 ;
36462 }
36463 }
36464 if (st->internal && DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
36465 duk_hcompiledfunction *f = (duk_hcompiledfunction *) h;
36466 DUK__COMMA(); duk_fb_put_cstring(fb, "__data:");
36467 duk__print_hbuffer(st, (duk_hbuffer *) DUK_HCOMPILEDFUNCTION_GET_DATA(NULL, f));
36468 DUK__COMMA(); duk_fb_sprintf(fb, "__nregs:%ld", (long) f->nregs);
36469 DUK__COMMA(); duk_fb_sprintf(fb, "__nargs:%ld", (long) f->nargs);
36470#if defined(DUK_USE_DEBUGGER_SUPPORT)
36471 DUK__COMMA(); duk_fb_sprintf(fb, "__start_line:%ld", (long) f->start_line);
36472 DUK__COMMA(); duk_fb_sprintf(fb, "__end_line:%ld", (long) f->end_line);
36473#endif
36474 DUK__COMMA(); duk_fb_put_cstring(fb, "__data:");
36475 duk__print_hbuffer(st, (duk_hbuffer *) DUK_HCOMPILEDFUNCTION_GET_DATA(NULL, f));
36476 } else if (st->internal && DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
36477 duk_hnativefunction *f = (duk_hnativefunction *) h;
36478 DUK__COMMA(); duk_fb_sprintf(fb, "__func:");
36479 duk_fb_put_funcptr(fb, (duk_uint8_t *) &f->func, sizeof(f->func));
36480 DUK__COMMA(); duk_fb_sprintf(fb, "__nargs:%ld", (long) f->nargs);
11fdf7f2 36481 DUK__COMMA(); duk_fb_sprintf(fb, "__magic:%ld", (long) f->magic);
7c673cae
FG
36482 } else if (st->internal && DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
36483 duk_hbufferobject *b = (duk_hbufferobject *) h;
36484 DUK__COMMA(); duk_fb_sprintf(fb, "__buf:");
36485 duk__print_hbuffer(st, (duk_hbuffer *) b->buf);
36486 DUK__COMMA(); duk_fb_sprintf(fb, "__offset:%ld", (long) b->offset);
36487 DUK__COMMA(); duk_fb_sprintf(fb, "__length:%ld", (long) b->length);
36488 DUK__COMMA(); duk_fb_sprintf(fb, "__shift:%ld", (long) b->shift);
36489 DUK__COMMA(); duk_fb_sprintf(fb, "__elemtype:%ld", (long) b->elem_type);
36490 } else if (st->internal && DUK_HOBJECT_IS_THREAD(h)) {
36491 duk_hthread *t = (duk_hthread *) h;
36492 DUK__COMMA(); duk_fb_sprintf(fb, "__strict:%ld", (long) t->strict);
36493 DUK__COMMA(); duk_fb_sprintf(fb, "__state:%ld", (long) t->state);
36494 DUK__COMMA(); duk_fb_sprintf(fb, "__unused1:%ld", (long) t->unused1);
36495 DUK__COMMA(); duk_fb_sprintf(fb, "__unused2:%ld", (long) t->unused2);
36496 DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_max:%ld", (long) t->valstack_max);
36497 DUK__COMMA(); duk_fb_sprintf(fb, "__callstack_max:%ld", (long) t->callstack_max);
36498 DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack_max:%ld", (long) t->catchstack_max);
36499 DUK__COMMA(); duk_fb_sprintf(fb, "__valstack:%p", (void *) t->valstack);
36500 DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_end:%p/%ld", (void *) t->valstack_end, (long) (t->valstack_end - t->valstack));
36501 DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_bottom:%p/%ld", (void *) t->valstack_bottom, (long) (t->valstack_bottom - t->valstack));
36502 DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_top:%p/%ld", (void *) t->valstack_top, (long) (t->valstack_top - t->valstack));
36503 DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack:%p", (void *) t->catchstack);
36504 DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack_size:%ld", (long) t->catchstack_size);
36505 DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack_top:%ld", (long) t->catchstack_top);
36506 DUK__COMMA(); duk_fb_sprintf(fb, "__resumer:"); duk__print_hobject(st, (duk_hobject *) t->resumer);
36507 /* XXX: print built-ins array? */
36508
36509 }
36510#ifdef DUK_USE_REFERENCE_COUNTING
36511 if (st->internal) {
36512 DUK__COMMA(); duk_fb_sprintf(fb, "__refcount:%lu", (unsigned long) DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h));
36513 }
36514#endif
36515 if (st->internal) {
36516 DUK__COMMA(); duk_fb_sprintf(fb, "__class:%ld", (long) DUK_HOBJECT_GET_CLASS_NUMBER(h));
36517 }
36518
11fdf7f2
TL
36519 DUK__COMMA(); duk_fb_sprintf(fb, "__heapptr:%p", (void *) h); /* own pointer */
36520
7c673cae 36521 /* prototype should be last, for readability */
11fdf7f2
TL
36522 if (DUK_HOBJECT_GET_PROTOTYPE(NULL, h)) {
36523 if (st->follow_proto) {
36524 DUK__COMMA(); duk_fb_put_cstring(fb, "__prototype:"); duk__print_hobject(st, DUK_HOBJECT_GET_PROTOTYPE(NULL, h));
36525 } else {
36526 DUK__COMMA(); duk_fb_sprintf(fb, "__prototype:%p", (void *) DUK_HOBJECT_GET_PROTOTYPE(NULL, h));
36527 }
7c673cae
FG
36528 }
36529
36530 duk_fb_put_cstring(fb, brace2);
36531
36532#if defined(DUK_USE_HOBJECT_HASH_PART)
36533 if (st->heavy && DUK_HOBJECT_GET_HSIZE(h) > 0) {
36534 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LANGLE);
36535 for (i = 0; i < DUK_HOBJECT_GET_HSIZE(h); i++) {
36536 duk_uint_t h_idx = DUK_HOBJECT_H_GET_INDEX(NULL, h, i);
36537 if (i > 0) {
36538 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_COMMA);
36539 }
36540 if (h_idx == DUK_HOBJECT_HASHIDX_UNUSED) {
36541 duk_fb_sprintf(fb, "u");
36542 } else if (h_idx == DUK_HOBJECT_HASHIDX_DELETED) {
36543 duk_fb_sprintf(fb, "d");
36544 } else {
36545 duk_fb_sprintf(fb, "%ld", (long) h_idx);
36546 }
36547 }
36548 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RANGLE);
36549 }
36550#endif
36551
36552 finished:
36553 st->depth--;
36554 if (pushed_loopstack) {
36555 st->loop_stack_index--;
36556 st->loop_stack[st->loop_stack_index] = NULL;
36557 }
36558}
36559
36560#undef DUK__COMMA
36561
36562DUK_LOCAL void duk__print_hbuffer(duk__dprint_state *st, duk_hbuffer *h) {
36563 duk_fixedbuffer *fb = st->fb;
36564 duk_size_t i, n;
36565 duk_uint8_t *p;
36566
36567 if (duk_fb_is_full(fb)) {
36568 return;
36569 }
36570
36571 /* terminal type: no depth check */
36572
36573 if (!h) {
36574 duk_fb_put_cstring(fb, "NULL");
36575 return;
36576 }
36577
36578 if (DUK_HBUFFER_HAS_DYNAMIC(h)) {
36579 if (DUK_HBUFFER_HAS_EXTERNAL(h)) {
36580 duk_hbuffer_external *g = (duk_hbuffer_external *) h;
36581 duk_fb_sprintf(fb, "buffer:external:%p:%ld",
36582 (void *) DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(NULL, g),
36583 (long) DUK_HBUFFER_EXTERNAL_GET_SIZE(g));
36584 } else {
36585 duk_hbuffer_dynamic *g = (duk_hbuffer_dynamic *) h;
36586 duk_fb_sprintf(fb, "buffer:dynamic:%p:%ld",
36587 (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(NULL, g),
36588 (long) DUK_HBUFFER_DYNAMIC_GET_SIZE(g));
36589 }
36590 } else {
36591 duk_fb_sprintf(fb, "buffer:fixed:%ld", (long) DUK_HBUFFER_GET_SIZE(h));
36592 }
36593
36594#ifdef DUK_USE_REFERENCE_COUNTING
36595 duk_fb_sprintf(fb, "/%lu", (unsigned long) DUK_HEAPHDR_GET_REFCOUNT(&h->hdr));
36596#endif
36597
36598 if (st->hexdump) {
36599 duk_fb_sprintf(fb, "=[");
36600 n = DUK_HBUFFER_GET_SIZE(h);
36601 p = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(NULL, h);
36602 for (i = 0; i < n; i++) {
36603 duk_fb_sprintf(fb, "%02lx", (unsigned long) p[i]);
36604 }
36605 duk_fb_sprintf(fb, "]");
36606 }
36607}
36608
36609DUK_LOCAL void duk__print_heaphdr(duk__dprint_state *st, duk_heaphdr *h) {
36610 duk_fixedbuffer *fb = st->fb;
36611
36612 if (duk_fb_is_full(fb)) {
36613 return;
36614 }
36615
36616 if (!h) {
36617 duk_fb_put_cstring(fb, "NULL");
36618 return;
36619 }
36620
36621 switch (DUK_HEAPHDR_GET_TYPE(h)) {
36622 case DUK_HTYPE_STRING:
36623 duk__print_hstring(st, (duk_hstring *) h, 1);
36624 break;
36625 case DUK_HTYPE_OBJECT:
36626 duk__print_hobject(st, (duk_hobject *) h);
36627 break;
36628 case DUK_HTYPE_BUFFER:
36629 duk__print_hbuffer(st, (duk_hbuffer *) h);
36630 break;
36631 default:
36632 duk_fb_sprintf(fb, "[unknown htype %ld]", (long) DUK_HEAPHDR_GET_TYPE(h));
36633 break;
36634 }
36635}
36636
36637DUK_LOCAL void duk__print_tval(duk__dprint_state *st, duk_tval *tv) {
36638 duk_fixedbuffer *fb = st->fb;
36639
36640 if (duk_fb_is_full(fb)) {
36641 return;
36642 }
36643
36644 /* depth check is done when printing an actual type */
36645
36646 if (st->heavy) {
36647 duk_fb_sprintf(fb, "(%p)", (void *) tv);
36648 }
36649
36650 if (!tv) {
36651 duk_fb_put_cstring(fb, "NULL");
36652 return;
36653 }
36654
36655 if (st->binary) {
36656 duk_size_t i;
36657 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LBRACKET);
36658 for (i = 0; i < (duk_size_t) sizeof(*tv); i++) {
36659 duk_fb_sprintf(fb, "%02lx", (unsigned long) ((duk_uint8_t *)tv)[i]);
36660 }
36661 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RBRACKET);
36662 }
36663
36664 if (st->heavy) {
36665 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LANGLE);
36666 }
36667 switch (DUK_TVAL_GET_TAG(tv)) {
36668 case DUK_TAG_UNDEFINED: {
11fdf7f2
TL
36669 duk_fb_put_cstring(fb, "undefined");
36670 break;
36671 }
36672 case DUK_TAG_UNUSED: {
36673 duk_fb_put_cstring(fb, "unused");
7c673cae
FG
36674 break;
36675 }
36676 case DUK_TAG_NULL: {
36677 duk_fb_put_cstring(fb, "null");
36678 break;
36679 }
36680 case DUK_TAG_BOOLEAN: {
36681 duk_fb_put_cstring(fb, DUK_TVAL_GET_BOOLEAN(tv) ? "true" : "false");
36682 break;
36683 }
36684 case DUK_TAG_STRING: {
36685 /* Note: string is a terminal heap object, so no depth check here */
36686 duk__print_hstring(st, DUK_TVAL_GET_STRING(tv), 1);
36687 break;
36688 }
36689 case DUK_TAG_OBJECT: {
36690 duk__print_hobject(st, DUK_TVAL_GET_OBJECT(tv));
36691 break;
36692 }
36693 case DUK_TAG_BUFFER: {
36694 duk__print_hbuffer(st, DUK_TVAL_GET_BUFFER(tv));
36695 break;
36696 }
36697 case DUK_TAG_POINTER: {
36698 duk_fb_sprintf(fb, "pointer:%p", (void *) DUK_TVAL_GET_POINTER(tv));
36699 break;
36700 }
36701 case DUK_TAG_LIGHTFUNC: {
36702 duk_c_function func;
36703 duk_small_uint_t lf_flags;
36704
36705 DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags);
36706 duk_fb_sprintf(fb, "lightfunc:");
36707 duk_fb_put_funcptr(fb, (duk_uint8_t *) &func, sizeof(func));
36708 duk_fb_sprintf(fb, ":%04lx", (long) lf_flags);
36709 break;
36710 }
36711#if defined(DUK_USE_FASTINT)
36712 case DUK_TAG_FASTINT:
36713#endif
36714 default: {
36715 /* IEEE double is approximately 16 decimal digits; print a couple extra */
11fdf7f2 36716 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
7c673cae
FG
36717 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
36718 duk_fb_sprintf(fb, "%.18g", (double) DUK_TVAL_GET_NUMBER(tv));
36719 break;
36720 }
36721 }
36722 if (st->heavy) {
36723 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RANGLE);
36724 }
36725}
36726
36727DUK_LOCAL void duk__print_instr(duk__dprint_state *st, duk_instr_t ins) {
36728 duk_fixedbuffer *fb = st->fb;
36729 duk_small_int_t op;
36730 const char *op_name;
36731 const char *extraop_name;
36732
36733 op = (duk_small_int_t) DUK_DEC_OP(ins);
36734 op_name = duk__bc_optab[op];
36735
36736 /* XXX: option to fix opcode length so it lines up nicely */
36737
36738 if (op == DUK_OP_EXTRA) {
36739 extraop_name = duk__bc_extraoptab[DUK_DEC_A(ins)];
36740
36741 duk_fb_sprintf(fb, "%s %ld, %ld",
36742 (const char *) extraop_name, (long) DUK_DEC_B(ins), (long) DUK_DEC_C(ins));
36743 } else if (op == DUK_OP_JUMP) {
36744 duk_int_t diff1 = DUK_DEC_ABC(ins) - DUK_BC_JUMP_BIAS; /* from next pc */
36745 duk_int_t diff2 = diff1 + 1; /* from curr pc */
36746
36747 duk_fb_sprintf(fb, "%s %ld (to pc%c%ld)",
36748 (const char *) op_name, (long) diff1,
36749 (int) (diff2 >= 0 ? '+' : '-'), /* char format: use int */
36750 (long) (diff2 >= 0 ? diff2 : -diff2));
36751 } else {
36752 duk_fb_sprintf(fb, "%s %ld, %ld, %ld",
36753 (const char *) op_name, (long) DUK_DEC_A(ins),
36754 (long) DUK_DEC_B(ins), (long) DUK_DEC_C(ins));
36755 }
36756}
36757
36758DUK_LOCAL void duk__print_opcode(duk__dprint_state *st, duk_small_int_t opcode) {
36759 duk_fixedbuffer *fb = st->fb;
36760
36761 if (opcode < DUK_BC_OP_MIN || opcode > DUK_BC_OP_MAX) {
36762 duk_fb_sprintf(fb, "?(%ld)", (long) opcode);
36763 } else {
36764 duk_fb_sprintf(fb, "%s", (const char *) duk__bc_optab[opcode]);
36765 }
36766}
36767
36768DUK_INTERNAL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const char *format, va_list ap) {
36769 duk_fixedbuffer fb;
36770 const char *p = format;
36771 const char *p_end = p + DUK_STRLEN(format);
36772 duk_int_t retval;
36773
36774 DUK_MEMZERO(&fb, sizeof(fb));
36775 fb.buffer = (duk_uint8_t *) str;
36776 fb.length = size;
36777 fb.offset = 0;
36778 fb.truncated = 0;
36779
36780 while (p < p_end) {
36781 char ch = *p++;
36782 const char *p_begfmt = NULL;
36783 duk_bool_t got_exclamation = 0;
36784 duk_bool_t got_long = 0; /* %lf, %ld etc */
36785 duk__dprint_state st;
36786
36787 if (ch != DUK_ASC_PERCENT) {
36788 duk_fb_put_byte(&fb, (duk_uint8_t) ch);
36789 continue;
36790 }
36791
36792 /*
36793 * Format tag parsing. Since we don't understand all the
36794 * possible format tags allowed, we just scan for a terminating
36795 * specifier and keep track of relevant modifiers that we do
36796 * understand. See man 3 printf.
36797 */
36798
36799 DUK_MEMZERO(&st, sizeof(st));
36800 st.fb = &fb;
36801 st.depth = 0;
36802 st.depth_limit = 1;
36803 st.loop_stack_index = 0;
36804 st.loop_stack_limit = DUK__LOOP_STACK_DEPTH;
36805
36806 p_begfmt = p - 1;
36807 while (p < p_end) {
36808 ch = *p++;
36809
36810 if (ch == DUK_ASC_STAR) {
36811 /* unsupported: would consume multiple args */
36812 goto error;
36813 } else if (ch == DUK_ASC_PERCENT) {
36814 duk_fb_put_byte(&fb, (duk_uint8_t) DUK_ASC_PERCENT);
36815 break;
36816 } else if (ch == DUK_ASC_EXCLAMATION) {
36817 got_exclamation = 1;
36818 } else if (!got_exclamation && ch == DUK_ASC_LC_L) {
36819 got_long = 1;
36820 } else if (got_exclamation && ch == DUK_ASC_LC_D) {
36821 st.depth_limit = DUK__DEEP_DEPTH_LIMIT;
36822 } else if (got_exclamation && ch == DUK_ASC_LC_P) {
36823 st.follow_proto = 1;
36824 } else if (got_exclamation && ch == DUK_ASC_LC_I) {
36825 st.internal = 1;
36826 } else if (got_exclamation && ch == DUK_ASC_LC_X) {
36827 st.hexdump = 1;
36828 } else if (got_exclamation && ch == DUK_ASC_LC_H) {
36829 st.heavy = 1;
36830 } else if (got_exclamation && ch == DUK_ASC_ATSIGN) {
36831 st.pointer = 1;
36832 } else if (got_exclamation && ch == DUK_ASC_HASH) {
36833 st.binary = 1;
36834 } else if (got_exclamation && ch == DUK_ASC_UC_T) {
36835 duk_tval *t = va_arg(ap, duk_tval *);
36836 if (st.pointer && !st.heavy) {
36837 duk_fb_sprintf(&fb, "(%p)", (void *) t);
36838 }
36839 duk__print_tval(&st, t);
36840 break;
36841 } else if (got_exclamation && ch == DUK_ASC_UC_O) {
36842 duk_heaphdr *t = va_arg(ap, duk_heaphdr *);
36843 if (st.pointer && !st.heavy) {
36844 duk_fb_sprintf(&fb, "(%p)", (void *) t);
36845 }
36846 duk__print_heaphdr(&st, t);
36847 break;
36848 } else if (got_exclamation && ch == DUK_ASC_UC_I) {
36849 duk_instr_t t = va_arg(ap, duk_instr_t);
36850 duk__print_instr(&st, t);
36851 break;
36852 } else if (got_exclamation && ch == DUK_ASC_UC_C) {
36853 long t = va_arg(ap, long);
36854 duk__print_opcode(&st, (duk_small_int_t) t);
36855 break;
36856 } else if (!got_exclamation && strchr(DUK__ALLOWED_STANDARD_SPECIFIERS, (int) ch)) {
36857 char fmtbuf[DUK__MAX_FORMAT_TAG_LENGTH];
36858 duk_size_t fmtlen;
36859
36860 DUK_ASSERT(p >= p_begfmt);
36861 fmtlen = (duk_size_t) (p - p_begfmt);
36862 if (fmtlen >= sizeof(fmtbuf)) {
36863 /* format is too large, abort */
36864 goto error;
36865 }
36866 DUK_MEMZERO(fmtbuf, sizeof(fmtbuf));
36867 DUK_MEMCPY(fmtbuf, p_begfmt, fmtlen);
36868
36869 /* assume exactly 1 arg, which is why '*' is forbidden; arg size still
36870 * depends on type though.
36871 */
36872
36873 if (ch == DUK_ASC_LC_F || ch == DUK_ASC_LC_G || ch == DUK_ASC_LC_E) {
36874 /* %f and %lf both consume a 'long' */
36875 double arg = va_arg(ap, double);
36876 duk_fb_sprintf(&fb, fmtbuf, arg);
36877 } else if (ch == DUK_ASC_LC_D && got_long) {
36878 /* %ld */
36879 long arg = va_arg(ap, long);
36880 duk_fb_sprintf(&fb, fmtbuf, arg);
36881 } else if (ch == DUK_ASC_LC_D) {
36882 /* %d; only 16 bits are guaranteed */
36883 int arg = va_arg(ap, int);
36884 duk_fb_sprintf(&fb, fmtbuf, arg);
36885 } else if (ch == DUK_ASC_LC_U && got_long) {
36886 /* %lu */
36887 unsigned long arg = va_arg(ap, unsigned long);
36888 duk_fb_sprintf(&fb, fmtbuf, arg);
36889 } else if (ch == DUK_ASC_LC_U) {
36890 /* %u; only 16 bits are guaranteed */
36891 unsigned int arg = va_arg(ap, unsigned int);
36892 duk_fb_sprintf(&fb, fmtbuf, arg);
36893 } else if (ch == DUK_ASC_LC_X && got_long) {
36894 /* %lx */
36895 unsigned long arg = va_arg(ap, unsigned long);
36896 duk_fb_sprintf(&fb, fmtbuf, arg);
36897 } else if (ch == DUK_ASC_LC_X) {
36898 /* %x; only 16 bits are guaranteed */
36899 unsigned int arg = va_arg(ap, unsigned int);
36900 duk_fb_sprintf(&fb, fmtbuf, arg);
36901 } else if (ch == DUK_ASC_LC_S) {
36902 /* %s */
36903 const char *arg = va_arg(ap, const char *);
36904 if (arg == NULL) {
36905 /* '%s' and NULL is not portable, so special case
36906 * it for debug printing.
36907 */
36908 duk_fb_sprintf(&fb, "NULL");
36909 } else {
36910 duk_fb_sprintf(&fb, fmtbuf, arg);
36911 }
36912 } else if (ch == DUK_ASC_LC_P) {
36913 /* %p */
36914 void *arg = va_arg(ap, void *);
36915 if (arg == NULL) {
36916 /* '%p' and NULL is portable, but special case it
36917 * anyway to get a standard NULL marker in logs.
36918 */
36919 duk_fb_sprintf(&fb, "NULL");
36920 } else {
36921 duk_fb_sprintf(&fb, fmtbuf, arg);
36922 }
36923 } else if (ch == DUK_ASC_LC_C) {
36924 /* '%c', passed concretely as int */
36925 int arg = va_arg(ap, int);
36926 duk_fb_sprintf(&fb, fmtbuf, arg);
36927 } else {
36928 /* Should not happen. */
36929 duk_fb_sprintf(&fb, "INVALID-FORMAT(%s)", (const char *) fmtbuf);
36930 }
36931 break;
36932 } else {
36933 /* ignore */
36934 }
36935 }
36936 }
36937 goto done;
36938
36939 error:
36940 duk_fb_put_cstring(&fb, "FMTERR");
36941 /* fall through */
36942
36943 done:
36944 retval = (duk_int_t) fb.offset;
36945 duk_fb_put_byte(&fb, (duk_uint8_t) 0);
36946
36947 /* return total chars written excluding terminator */
36948 return retval;
36949}
36950
36951#if 0 /*unused*/
36952DUK_INTERNAL duk_int_t duk_debug_snprintf(char *str, duk_size_t size, const char *format, ...) {
36953 duk_int_t retval;
36954 va_list ap;
36955 va_start(ap, format);
36956 retval = duk_debug_vsnprintf(str, size, format, ap);
36957 va_end(ap);
36958 return retval;
36959}
36960#endif
36961
36962/* Formatting function pointers is tricky: there is no standard pointer for
36963 * function pointers and the size of a function pointer may depend on the
36964 * specific pointer type. This helper formats a function pointer based on
36965 * its memory layout to get something useful on most platforms.
36966 */
36967DUK_INTERNAL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_uint8_t *fptr, duk_size_t fptr_size) {
36968 duk_size_t i;
36969 duk_uint8_t *p = (duk_uint8_t *) buf;
36970 duk_uint8_t *p_end = (duk_uint8_t *) (buf + buf_size - 1);
36971
36972 DUK_MEMZERO(buf, buf_size);
36973
36974 for (i = 0; i < fptr_size; i++) {
36975 duk_int_t left = (duk_int_t) (p_end - p);
36976 duk_uint8_t ch;
36977 if (left <= 0) {
36978 break;
36979 }
36980
36981 /* Quite approximate but should be useful for little and big endian. */
36982#ifdef DUK_USE_INTEGER_BE
36983 ch = fptr[i];
36984#else
36985 ch = fptr[fptr_size - 1 - i];
36986#endif
36987 p += DUK_SNPRINTF((char *) p, left, "%02lx", (unsigned long) ch);
36988 }
36989}
36990
36991#endif /* DUK_USE_DEBUG */
7c673cae
FG
36992/*
36993 * Duktape debugger
36994 */
36995
36996/* include removed: duk_internal.h */
36997
36998#if defined(DUK_USE_DEBUGGER_SUPPORT)
36999
37000/*
37001 * Helper structs
37002 */
37003
37004typedef union {
37005 void *p;
37006 duk_uint_t b[1];
37007 /* Use b[] to access the size of the union, which is strictly not
37008 * correct. Can't use fixed size unless there's feature detection
37009 * for pointer byte size.
37010 */
37011} duk__ptr_union;
37012
37013/*
37014 * Detach handling
37015 */
37016
11fdf7f2 37017#define DUK__SET_CONN_BROKEN(thr,reason) do { \
7c673cae 37018 /* For now shared handler is fine. */ \
11fdf7f2 37019 duk__debug_do_detach1((thr)->heap, (reason)); \
7c673cae
FG
37020 } while (0)
37021
11fdf7f2
TL
37022DUK_LOCAL void duk__debug_do_detach1(duk_heap *heap, duk_int_t reason) {
37023 /* Can be called multiple times with no harm. Mark the transport
37024 * bad (dbg_read_cb == NULL) and clear state except for the detached
37025 * callback and the udata field. The detached callback is delayed
37026 * to the message loop so that it can be called between messages;
37027 * this avoids corner cases related to immediate debugger reattach
37028 * inside the detached callback.
37029 */
37030
37031 if (heap->dbg_detaching) {
37032 DUK_D(DUK_DPRINT("debugger already detaching, ignore detach1"));
37033 return;
37034 }
37035
37036 DUK_D(DUK_DPRINT("debugger transport detaching, marking transport broken"));
37037
37038 heap->dbg_detaching = 1; /* prevent multiple in-progress detaches */
37039
37040 if (heap->dbg_write_cb != NULL) {
37041 duk_hthread *thr;
37042
37043 thr = heap->heap_thread;
37044 DUK_ASSERT(thr != NULL);
37045
37046 duk_debug_write_notify(thr, DUK_DBG_CMD_DETACHING);
37047 duk_debug_write_int(thr, reason);
37048 duk_debug_write_eom(thr);
37049 }
7c673cae
FG
37050
37051 heap->dbg_read_cb = NULL;
37052 heap->dbg_write_cb = NULL;
37053 heap->dbg_peek_cb = NULL;
37054 heap->dbg_read_flush_cb = NULL;
37055 heap->dbg_write_flush_cb = NULL;
11fdf7f2
TL
37056 heap->dbg_request_cb = NULL;
37057 /* heap->dbg_detached_cb: keep */
37058 /* heap->dbg_udata: keep */
37059 /* heap->dbg_processing: keep on purpose to avoid debugger re-entry in detaching state */
7c673cae
FG
37060 heap->dbg_paused = 0;
37061 heap->dbg_state_dirty = 0;
37062 heap->dbg_force_restart = 0;
37063 heap->dbg_step_type = 0;
37064 heap->dbg_step_thread = NULL;
37065 heap->dbg_step_csindex = 0;
37066 heap->dbg_step_startline = 0;
11fdf7f2 37067 heap->dbg_have_next_byte = 0;
7c673cae
FG
37068
37069 /* Ensure there are no stale active breakpoint pointers.
37070 * Breakpoint list is currently kept - we could empty it
37071 * here but we'd need to handle refcounts correctly, and
37072 * we'd need a 'thr' reference for that.
37073 *
37074 * XXX: clear breakpoint on either attach or detach?
37075 */
37076 heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL;
37077}
37078
11fdf7f2
TL
37079DUK_LOCAL void duk__debug_do_detach2(duk_heap *heap) {
37080 duk_debug_detached_function detached_cb;
37081 void *detached_udata;
37082
37083 /* Safe to call multiple times. */
37084
37085 detached_cb = heap->dbg_detached_cb;
37086 detached_udata = heap->dbg_udata;
37087 heap->dbg_detached_cb = NULL;
37088 heap->dbg_udata = NULL;
37089
37090 if (detached_cb) {
37091 /* Careful here: state must be wiped before the call
37092 * so that we can cleanly handle a re-attach from
37093 * inside the callback.
37094 */
37095 DUK_D(DUK_DPRINT("detached during message loop, delayed call to detached_cb"));
37096 detached_cb(detached_udata);
37097 }
37098
37099 heap->dbg_detaching = 0;
37100}
37101
37102DUK_INTERNAL void duk_debug_do_detach(duk_heap *heap) {
37103 duk__debug_do_detach1(heap, 0);
37104 duk__debug_do_detach2(heap);
37105}
37106
37107/* Called on a read/write error: NULL all callbacks except the detached
37108 * callback so that we never accidentally call them after a read/write
37109 * error has been indicated. This is especially important for the transport
37110 * I/O callbacks to fulfill guaranteed callback semantics.
37111 */
37112DUK_LOCAL void duk__debug_null_most_callbacks(duk_hthread *thr) {
37113 duk_heap *heap;
37114 heap = thr->heap;
37115 DUK_D(DUK_DPRINT("transport read/write error, NULL all callbacks expected detached"));
37116 heap->dbg_read_cb = NULL;
37117 heap->dbg_write_cb = NULL; /* this is especially critical to avoid another write call in detach1() */
37118 heap->dbg_peek_cb = NULL;
37119 heap->dbg_read_flush_cb = NULL;
37120 heap->dbg_write_flush_cb = NULL;
37121 heap->dbg_request_cb = NULL;
37122 /* keep heap->dbg_detached_cb */
37123}
37124
7c673cae
FG
37125/*
37126 * Debug connection peek and flush primitives
37127 */
37128
37129DUK_INTERNAL duk_bool_t duk_debug_read_peek(duk_hthread *thr) {
37130 duk_heap *heap;
37131
37132 DUK_ASSERT(thr != NULL);
37133 heap = thr->heap;
37134 DUK_ASSERT(heap != NULL);
37135
37136 if (heap->dbg_read_cb == NULL) {
37137 DUK_D(DUK_DPRINT("attempt to peek in detached state, return zero (= no data)"));
37138 return 0;
37139 }
37140 if (heap->dbg_peek_cb == NULL) {
37141 DUK_DD(DUK_DDPRINT("no peek callback, return zero (= no data)"));
37142 return 0;
37143 }
37144
37145 return (duk_bool_t) (heap->dbg_peek_cb(heap->dbg_udata) > 0);
37146}
37147
37148DUK_INTERNAL void duk_debug_read_flush(duk_hthread *thr) {
37149 duk_heap *heap;
37150
37151 DUK_ASSERT(thr != NULL);
37152 heap = thr->heap;
37153 DUK_ASSERT(heap != NULL);
37154
37155 if (heap->dbg_read_cb == NULL) {
37156 DUK_D(DUK_DPRINT("attempt to read flush in detached state, ignore"));
37157 return;
37158 }
37159 if (heap->dbg_read_flush_cb == NULL) {
37160 DUK_DD(DUK_DDPRINT("no read flush callback, ignore"));
37161 return;
37162 }
37163
37164 heap->dbg_read_flush_cb(heap->dbg_udata);
37165}
37166
37167DUK_INTERNAL void duk_debug_write_flush(duk_hthread *thr) {
37168 duk_heap *heap;
37169
37170 DUK_ASSERT(thr != NULL);
37171 heap = thr->heap;
37172 DUK_ASSERT(heap != NULL);
37173
37174 if (heap->dbg_read_cb == NULL) {
37175 DUK_D(DUK_DPRINT("attempt to write flush in detached state, ignore"));
37176 return;
37177 }
37178 if (heap->dbg_write_flush_cb == NULL) {
37179 DUK_DD(DUK_DDPRINT("no write flush callback, ignore"));
37180 return;
37181 }
37182
37183 heap->dbg_write_flush_cb(heap->dbg_udata);
37184}
37185
37186/*
37187 * Debug connection skip primitives
37188 */
37189
37190/* Skip fully. */
37191DUK_INTERNAL void duk_debug_skip_bytes(duk_hthread *thr, duk_size_t length) {
37192 duk_uint8_t dummy[64];
37193 duk_size_t now;
37194
37195 DUK_ASSERT(thr != NULL);
37196
37197 while (length > 0) {
37198 now = (length > sizeof(dummy) ? sizeof(dummy) : length);
37199 duk_debug_read_bytes(thr, dummy, now);
37200 length -= now;
37201 }
37202}
37203
37204DUK_INTERNAL void duk_debug_skip_byte(duk_hthread *thr) {
37205 DUK_ASSERT(thr != NULL);
37206
37207 (void) duk_debug_read_byte(thr);
37208}
37209
37210/*
37211 * Debug connection read primitives
37212 */
37213
11fdf7f2
TL
37214/* Peek ahead in the stream one byte. */
37215DUK_INTERNAL uint8_t duk_debug_peek_byte(duk_hthread *thr) {
37216 /* It is important not to call this if the last byte read was an EOM.
37217 * Reading ahead in this scenario would cause unnecessary blocking if
37218 * another message is not available.
37219 */
37220
37221 duk_uint8_t x;
37222
37223 x = duk_debug_read_byte(thr);
37224 thr->heap->dbg_have_next_byte = 1;
37225 thr->heap->dbg_next_byte = x;
37226 return x;
37227}
37228
7c673cae
FG
37229/* Read fully. */
37230DUK_INTERNAL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_size_t length) {
37231 duk_heap *heap;
37232 duk_uint8_t *p;
37233 duk_size_t left;
37234 duk_size_t got;
37235
37236 DUK_ASSERT(thr != NULL);
37237 heap = thr->heap;
37238 DUK_ASSERT(heap != NULL);
37239
37240 if (heap->dbg_read_cb == NULL) {
37241 DUK_D(DUK_DPRINT("attempt to read %ld bytes in detached state, return zero data", (long) length));
37242 goto fail;
37243 }
37244
11fdf7f2 37245 /* NOTE: length may be zero */
7c673cae 37246 p = data;
11fdf7f2
TL
37247 if (length >= 1 && heap->dbg_have_next_byte) {
37248 heap->dbg_have_next_byte = 0;
37249 *p++ = heap->dbg_next_byte;
37250 }
7c673cae
FG
37251 for (;;) {
37252 left = (duk_size_t) ((data + length) - p);
37253 if (left == 0) {
37254 break;
37255 }
37256 DUK_ASSERT(heap->dbg_read_cb != NULL);
37257 DUK_ASSERT(left >= 1);
37258#if defined(DUK_USE_DEBUGGER_TRANSPORT_TORTURE)
37259 left = 1;
37260#endif
37261 got = heap->dbg_read_cb(heap->dbg_udata, (char *) p, left);
37262 if (got == 0 || got > left) {
37263 DUK_D(DUK_DPRINT("connection error during read, return zero data"));
11fdf7f2
TL
37264 duk__debug_null_most_callbacks(thr); /* avoid calling write callback in detach1() */
37265 DUK__SET_CONN_BROKEN(thr, 1);
7c673cae
FG
37266 goto fail;
37267 }
37268 p += got;
37269 }
37270 return;
37271
37272 fail:
37273 DUK_MEMZERO((void *) data, (size_t) length);
37274}
37275
37276DUK_INTERNAL duk_uint8_t duk_debug_read_byte(duk_hthread *thr) {
7c673cae
FG
37277 duk_uint8_t x;
37278
7c673cae 37279 x = 0; /* just in case callback is broken and won't write 'x' */
11fdf7f2 37280 duk_debug_read_bytes(thr, &x, 1);
7c673cae
FG
37281 return x;
37282}
37283
37284DUK_LOCAL duk_uint32_t duk__debug_read_uint32_raw(duk_hthread *thr) {
37285 duk_uint8_t buf[4];
37286
37287 DUK_ASSERT(thr != NULL);
37288
37289 duk_debug_read_bytes(thr, buf, 4);
37290 return ((duk_uint32_t) buf[0] << 24) |
37291 ((duk_uint32_t) buf[1] << 16) |
37292 ((duk_uint32_t) buf[2] << 8) |
37293 (duk_uint32_t) buf[3];
37294}
37295
37296DUK_LOCAL duk_uint32_t duk__debug_read_int32_raw(duk_hthread *thr) {
37297 return (duk_int32_t) duk__debug_read_uint32_raw(thr);
37298}
37299
37300DUK_LOCAL duk_uint16_t duk__debug_read_uint16_raw(duk_hthread *thr) {
37301 duk_uint8_t buf[2];
37302
37303 DUK_ASSERT(thr != NULL);
37304
37305 duk_debug_read_bytes(thr, buf, 2);
37306 return ((duk_uint16_t) buf[0] << 8) |
37307 (duk_uint16_t) buf[1];
37308}
37309
37310DUK_INTERNAL duk_int32_t duk_debug_read_int(duk_hthread *thr) {
37311 duk_small_uint_t x;
37312 duk_small_uint_t t;
37313
37314 DUK_ASSERT(thr != NULL);
37315
37316 x = duk_debug_read_byte(thr);
37317 if (x >= 0xc0) {
37318 t = duk_debug_read_byte(thr);
37319 return (duk_int32_t) (((x - 0xc0) << 8) + t);
37320 } else if (x >= 0x80) {
37321 return (duk_int32_t) (x - 0x80);
11fdf7f2 37322 } else if (x == DUK_DBG_IB_INT4) {
7c673cae
FG
37323 return (duk_int32_t) duk__debug_read_uint32_raw(thr);
37324 }
37325
37326 DUK_D(DUK_DPRINT("debug connection error: failed to decode int"));
11fdf7f2 37327 DUK__SET_CONN_BROKEN(thr, 1);
7c673cae
FG
37328 return 0;
37329}
37330
37331DUK_LOCAL duk_hstring *duk__debug_read_hstring_raw(duk_hthread *thr, duk_uint32_t len) {
37332 duk_context *ctx = (duk_context *) thr;
37333 duk_uint8_t buf[31];
37334 duk_uint8_t *p;
37335
37336 if (len <= sizeof(buf)) {
37337 duk_debug_read_bytes(thr, buf, (duk_size_t) len);
37338 duk_push_lstring(ctx, (const char *) buf, (duk_size_t) len);
37339 } else {
37340 p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len);
37341 DUK_ASSERT(p != NULL);
37342 duk_debug_read_bytes(thr, p, (duk_size_t) len);
37343 duk_to_string(ctx, -1);
37344 }
37345
37346 return duk_require_hstring(ctx, -1);
37347}
37348
37349DUK_INTERNAL duk_hstring *duk_debug_read_hstring(duk_hthread *thr) {
37350 duk_context *ctx = (duk_context *) thr;
37351 duk_small_uint_t x;
37352 duk_uint32_t len;
37353
37354 DUK_ASSERT(thr != NULL);
37355
37356 x = duk_debug_read_byte(thr);
37357 if (x >= 0x60 && x <= 0x7f) {
37358 /* For short strings, use a fixed temp buffer. */
37359 len = (duk_uint32_t) (x - 0x60);
11fdf7f2 37360 } else if (x == DUK_DBG_IB_STR2) {
7c673cae 37361 len = (duk_uint32_t) duk__debug_read_uint16_raw(thr);
11fdf7f2 37362 } else if (x == DUK_DBG_IB_STR4) {
7c673cae
FG
37363 len = (duk_uint32_t) duk__debug_read_uint32_raw(thr);
37364 } else {
37365 goto fail;
37366 }
37367
37368 return duk__debug_read_hstring_raw(thr, len);
37369
37370 fail:
37371 DUK_D(DUK_DPRINT("debug connection error: failed to decode int"));
11fdf7f2 37372 DUK__SET_CONN_BROKEN(thr, 1);
7c673cae
FG
37373 duk_push_hstring_stridx(thr, DUK_STRIDX_EMPTY_STRING); /* always push some string */
37374 return duk_require_hstring(ctx, -1);
37375}
37376
37377DUK_LOCAL duk_hbuffer *duk__debug_read_hbuffer_raw(duk_hthread *thr, duk_uint32_t len) {
37378 duk_context *ctx = (duk_context *) thr;
37379 duk_uint8_t *p;
37380
37381 p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len);
37382 DUK_ASSERT(p != NULL);
37383 duk_debug_read_bytes(thr, p, (duk_size_t) len);
37384
37385 return duk_require_hbuffer(ctx, -1);
37386}
37387
11fdf7f2 37388DUK_LOCAL void *duk__debug_read_pointer_raw(duk_hthread *thr) {
7c673cae 37389 duk_small_uint_t x;
11fdf7f2 37390 duk__ptr_union pu;
7c673cae
FG
37391
37392 DUK_ASSERT(thr != NULL);
37393
37394 x = duk_debug_read_byte(thr);
37395 if (x != sizeof(pu)) {
37396 goto fail;
37397 }
37398 duk_debug_read_bytes(thr, (duk_uint8_t *) &pu.p, sizeof(pu));
37399#if defined(DUK_USE_INTEGER_LE)
37400 duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu));
37401#endif
11fdf7f2 37402 return (void *) pu.p;
7c673cae
FG
37403
37404 fail:
37405 DUK_D(DUK_DPRINT("debug connection error: failed to decode pointer"));
11fdf7f2
TL
37406 DUK__SET_CONN_BROKEN(thr, 1);
37407 return (void *) NULL;
7c673cae
FG
37408}
37409
37410DUK_LOCAL duk_double_t duk__debug_read_double_raw(duk_hthread *thr) {
37411 duk_double_union du;
37412
37413 DUK_ASSERT(sizeof(du.uc) == 8);
37414 duk_debug_read_bytes(thr, (duk_uint8_t *) du.uc, sizeof(du.uc));
37415 DUK_DBLUNION_DOUBLE_NTOH(&du);
37416 return du.d;
37417}
37418
11fdf7f2
TL
37419#if 0
37420DUK_INTERNAL duk_heaphdr *duk_debug_read_heapptr(duk_hthread *thr) {
37421 duk_small_uint_t x;
37422
37423 DUK_ASSERT(thr != NULL);
37424
37425 x = duk_debug_read_byte(thr);
37426 if (x != DUK_DBG_IB_HEAPPTR) {
37427 goto fail;
37428 }
37429
37430 return (duk_heaphdr *) duk__debug_read_pointer_raw(thr);
37431
37432 fail:
37433 DUK_D(DUK_DPRINT("debug connection error: failed to decode heapptr"));
37434 DUK__SET_CONN_BROKEN(thr, 1);
37435 return NULL;
37436}
37437#endif
37438
37439DUK_INTERNAL duk_heaphdr *duk_debug_read_any_ptr(duk_hthread *thr) {
37440 duk_small_uint_t x;
37441
37442 DUK_ASSERT(thr != NULL);
37443
37444 x = duk_debug_read_byte(thr);
37445 switch (x) {
37446 case DUK_DBG_IB_OBJECT:
37447 case DUK_DBG_IB_POINTER:
37448 case DUK_DBG_IB_HEAPPTR:
37449 /* Accept any pointer-like value; for 'object' dvalue, read
37450 * and ignore the class number.
37451 */
37452 if (x == DUK_DBG_IB_OBJECT) {
37453 duk_debug_skip_byte(thr);
37454 }
37455 break;
37456 default:
37457 goto fail;
37458 }
37459
37460 return (duk_heaphdr *) duk__debug_read_pointer_raw(thr);
37461
37462 fail:
37463 DUK_D(DUK_DPRINT("debug connection error: failed to decode any pointer (object, pointer, heapptr)"));
37464 DUK__SET_CONN_BROKEN(thr, 1);
37465 return NULL;
37466}
37467
37468DUK_INTERNAL duk_tval *duk_debug_read_tval(duk_hthread *thr) {
7c673cae
FG
37469 duk_context *ctx = (duk_context *) thr;
37470 duk_uint8_t x;
37471 duk_uint_t t;
37472 duk_uint32_t len;
37473
37474 DUK_ASSERT(thr != NULL);
37475
37476 x = duk_debug_read_byte(thr);
37477
37478 if (x >= 0xc0) {
37479 t = (duk_uint_t) (x - 0xc0);
37480 t = (t << 8) + duk_debug_read_byte(thr);
37481 duk_push_uint(ctx, (duk_uint_t) t);
11fdf7f2 37482 goto return_ptr;
7c673cae
FG
37483 }
37484 if (x >= 0x80) {
37485 duk_push_uint(ctx, (duk_uint_t) (x - 0x80));
11fdf7f2 37486 goto return_ptr;
7c673cae
FG
37487 }
37488 if (x >= 0x60) {
37489 len = (duk_uint32_t) (x - 0x60);
37490 duk__debug_read_hstring_raw(thr, len);
11fdf7f2 37491 goto return_ptr;
7c673cae
FG
37492 }
37493
37494 switch (x) {
11fdf7f2 37495 case DUK_DBG_IB_INT4: {
7c673cae
FG
37496 duk_int32_t i = duk__debug_read_int32_raw(thr);
37497 duk_push_i32(ctx, i);
37498 break;
37499 }
11fdf7f2 37500 case DUK_DBG_IB_STR4: {
7c673cae
FG
37501 len = duk__debug_read_uint32_raw(thr);
37502 duk__debug_read_hstring_raw(thr, len);
37503 break;
11fdf7f2
TL
37504 }
37505 case DUK_DBG_IB_STR2: {
7c673cae
FG
37506 len = duk__debug_read_uint16_raw(thr);
37507 duk__debug_read_hstring_raw(thr, len);
37508 break;
11fdf7f2
TL
37509 }
37510 case DUK_DBG_IB_BUF4: {
7c673cae
FG
37511 len = duk__debug_read_uint32_raw(thr);
37512 duk__debug_read_hbuffer_raw(thr, len);
37513 break;
11fdf7f2
TL
37514 }
37515 case DUK_DBG_IB_BUF2: {
7c673cae
FG
37516 len = duk__debug_read_uint16_raw(thr);
37517 duk__debug_read_hbuffer_raw(thr, len);
37518 break;
11fdf7f2
TL
37519 }
37520 case DUK_DBG_IB_UNDEFINED: {
7c673cae
FG
37521 duk_push_undefined(ctx);
37522 break;
11fdf7f2
TL
37523 }
37524 case DUK_DBG_IB_NULL: {
7c673cae
FG
37525 duk_push_null(ctx);
37526 break;
11fdf7f2
TL
37527 }
37528 case DUK_DBG_IB_TRUE: {
7c673cae
FG
37529 duk_push_true(ctx);
37530 break;
11fdf7f2
TL
37531 }
37532 case DUK_DBG_IB_FALSE: {
7c673cae
FG
37533 duk_push_false(ctx);
37534 break;
11fdf7f2
TL
37535 }
37536 case DUK_DBG_IB_NUMBER: {
7c673cae
FG
37537 duk_double_t d;
37538 d = duk__debug_read_double_raw(thr);
37539 duk_push_number(ctx, d);
37540 break;
37541 }
11fdf7f2
TL
37542 case DUK_DBG_IB_OBJECT: {
37543 duk_heaphdr *h;
37544 duk_debug_skip_byte(thr);
37545 h = (duk_heaphdr *) duk__debug_read_pointer_raw(thr);
37546 duk_push_heapptr(thr, (void *) h);
37547 break;
37548 }
37549 case DUK_DBG_IB_POINTER: {
37550 void *ptr;
7c673cae 37551 ptr = duk__debug_read_pointer_raw(thr);
11fdf7f2 37552 duk_push_pointer(thr, ptr);
7c673cae
FG
37553 break;
37554 }
11fdf7f2
TL
37555 case DUK_DBG_IB_LIGHTFUNC: {
37556 /* XXX: Not needed for now, so not implemented. Note that
37557 * function pointers may have different size/layout than
37558 * a void pointer.
37559 */
7c673cae
FG
37560 DUK_D(DUK_DPRINT("reading lightfunc values unimplemented"));
37561 goto fail;
11fdf7f2
TL
37562 }
37563 case DUK_DBG_IB_HEAPPTR: {
7c673cae
FG
37564 duk_heaphdr *h;
37565 h = (duk_heaphdr *) duk__debug_read_pointer_raw(thr);
37566 duk_push_heapptr(thr, (void *) h);
37567 break;
37568 }
11fdf7f2 37569 case DUK_DBG_IB_UNUSED: /* unused: not accepted in inbound messages */
7c673cae
FG
37570 default:
37571 goto fail;
37572 }
37573
11fdf7f2
TL
37574 return_ptr:
37575 return DUK_GET_TVAL_NEGIDX(thr, -1);
7c673cae
FG
37576
37577 fail:
37578 DUK_D(DUK_DPRINT("debug connection error: failed to decode tval"));
11fdf7f2
TL
37579 DUK__SET_CONN_BROKEN(thr, 1);
37580 return NULL;
7c673cae
FG
37581}
37582
37583/*
37584 * Debug connection write primitives
37585 */
37586
37587/* Write fully. */
37588DUK_INTERNAL void duk_debug_write_bytes(duk_hthread *thr, const duk_uint8_t *data, duk_size_t length) {
37589 duk_heap *heap;
37590 const duk_uint8_t *p;
37591 duk_size_t left;
37592 duk_size_t got;
37593
37594 DUK_ASSERT(thr != NULL);
37595 DUK_ASSERT(length == 0 || data != NULL);
37596 heap = thr->heap;
37597 DUK_ASSERT(heap != NULL);
37598
37599 if (heap->dbg_write_cb == NULL) {
37600 DUK_D(DUK_DPRINT("attempt to write %ld bytes in detached state, ignore", (long) length));
37601 return;
37602 }
37603 if (length == 0) {
37604 /* Avoid doing an actual write callback with length == 0,
37605 * because that's reserved for a write flush.
37606 */
37607 return;
37608 }
37609 DUK_ASSERT(data != NULL);
37610
37611 p = data;
37612 for (;;) {
37613 left = (duk_size_t) ((data + length) - p);
37614 if (left == 0) {
37615 break;
37616 }
37617 DUK_ASSERT(heap->dbg_write_cb != NULL);
37618 DUK_ASSERT(left >= 1);
37619#if defined(DUK_USE_DEBUGGER_TRANSPORT_TORTURE)
37620 left = 1;
37621#endif
37622 got = heap->dbg_write_cb(heap->dbg_udata, (const char *) p, left);
37623 if (got == 0 || got > left) {
11fdf7f2 37624 duk__debug_null_most_callbacks(thr); /* avoid calling write callback in detach1() */
7c673cae 37625 DUK_D(DUK_DPRINT("connection error during write"));
11fdf7f2 37626 DUK__SET_CONN_BROKEN(thr, 1);
7c673cae
FG
37627 return;
37628 }
37629 p += got;
37630 }
37631}
37632
37633DUK_INTERNAL void duk_debug_write_byte(duk_hthread *thr, duk_uint8_t x) {
11fdf7f2 37634 duk_debug_write_bytes(thr, (const duk_uint8_t *) &x, 1);
7c673cae
FG
37635}
37636
37637DUK_INTERNAL void duk_debug_write_unused(duk_hthread *thr) {
11fdf7f2 37638 duk_debug_write_byte(thr, DUK_DBG_IB_UNUSED);
7c673cae
FG
37639}
37640
37641DUK_INTERNAL void duk_debug_write_undefined(duk_hthread *thr) {
11fdf7f2
TL
37642 duk_debug_write_byte(thr, DUK_DBG_IB_UNDEFINED);
37643}
37644
37645#if defined(DUK_USE_DEBUGGER_INSPECT)
37646DUK_INTERNAL void duk_debug_write_null(duk_hthread *thr) {
37647 duk_debug_write_byte(thr, DUK_DBG_IB_NULL);
37648}
37649#endif
37650
37651DUK_INTERNAL void duk_debug_write_boolean(duk_hthread *thr, duk_uint_t val) {
37652 duk_debug_write_byte(thr, val ? DUK_DBG_IB_TRUE : DUK_DBG_IB_FALSE);
7c673cae
FG
37653}
37654
37655/* Write signed 32-bit integer. */
37656DUK_INTERNAL void duk_debug_write_int(duk_hthread *thr, duk_int32_t x) {
37657 duk_uint8_t buf[5];
37658 duk_size_t len;
37659
37660 DUK_ASSERT(thr != NULL);
37661
37662 if (x >= 0 && x <= 0x3fL) {
37663 buf[0] = (duk_uint8_t) (0x80 + x);
37664 len = 1;
37665 } else if (x >= 0 && x <= 0x3fffL) {
37666 buf[0] = (duk_uint8_t) (0xc0 + (x >> 8));
37667 buf[1] = (duk_uint8_t) (x & 0xff);
37668 len = 2;
37669 } else {
37670 /* Signed integers always map to 4 bytes now. */
11fdf7f2 37671 buf[0] = (duk_uint8_t) DUK_DBG_IB_INT4;
7c673cae
FG
37672 buf[1] = (duk_uint8_t) ((x >> 24) & 0xff);
37673 buf[2] = (duk_uint8_t) ((x >> 16) & 0xff);
37674 buf[3] = (duk_uint8_t) ((x >> 8) & 0xff);
37675 buf[4] = (duk_uint8_t) (x & 0xff);
37676 len = 5;
37677 }
37678 duk_debug_write_bytes(thr, buf, len);
37679}
37680
37681/* Write unsigned 32-bit integer. */
37682DUK_INTERNAL void duk_debug_write_uint(duk_hthread *thr, duk_uint32_t x) {
11fdf7f2
TL
37683 /* The debugger protocol doesn't support a plain integer encoding for
37684 * the full 32-bit unsigned range (only 32-bit signed). For now,
37685 * unsigned 32-bit values simply written as signed ones. This is not
37686 * a concrete issue except for 32-bit heaphdr fields. Proper solutions
37687 * would be to (a) write such integers as IEEE doubles or (b) add an
37688 * unsigned 32-bit dvalue.
7c673cae 37689 */
11fdf7f2
TL
37690 if (x >= 0x80000000UL) {
37691 DUK_D(DUK_DPRINT("writing unsigned integer 0x%08lx as signed integer",
37692 (long) x));
37693 }
7c673cae
FG
37694 duk_debug_write_int(thr, (duk_int32_t) x);
37695}
37696
37697DUK_INTERNAL void duk_debug_write_strbuf(duk_hthread *thr, const char *data, duk_size_t length, duk_uint8_t marker_base) {
37698 duk_uint8_t buf[5];
37699 duk_size_t buflen;
37700
37701 DUK_ASSERT(thr != NULL);
37702 DUK_ASSERT(length == 0 || data != NULL);
37703
11fdf7f2 37704 if (length <= 0x1fUL && marker_base == DUK_DBG_IB_STR4) {
7c673cae
FG
37705 /* For strings, special form for short lengths. */
37706 buf[0] = (duk_uint8_t) (0x60 + length);
37707 buflen = 1;
37708 } else if (length <= 0xffffUL) {
37709 buf[0] = (duk_uint8_t) (marker_base + 1);
37710 buf[1] = (duk_uint8_t) (length >> 8);
37711 buf[2] = (duk_uint8_t) (length & 0xff);
37712 buflen = 3;
37713 } else {
37714 buf[0] = (duk_uint8_t) marker_base;
37715 buf[1] = (duk_uint8_t) (length >> 24);
37716 buf[2] = (duk_uint8_t) ((length >> 16) & 0xff);
37717 buf[3] = (duk_uint8_t) ((length >> 8) & 0xff);
37718 buf[4] = (duk_uint8_t) (length & 0xff);
37719 buflen = 5;
37720 }
37721
37722 duk_debug_write_bytes(thr, (const duk_uint8_t *) buf, buflen);
37723 duk_debug_write_bytes(thr, (const duk_uint8_t *) data, length);
37724}
37725
37726DUK_INTERNAL void duk_debug_write_string(duk_hthread *thr, const char *data, duk_size_t length) {
11fdf7f2 37727 duk_debug_write_strbuf(thr, data, length, DUK_DBG_IB_STR4);
7c673cae
FG
37728}
37729
37730DUK_INTERNAL void duk_debug_write_cstring(duk_hthread *thr, const char *data) {
37731 DUK_ASSERT(thr != NULL);
37732
37733 duk_debug_write_string(thr,
37734 data,
37735 data ? DUK_STRLEN(data) : 0);
37736}
37737
37738DUK_INTERNAL void duk_debug_write_hstring(duk_hthread *thr, duk_hstring *h) {
37739 DUK_ASSERT(thr != NULL);
37740
37741 /* XXX: differentiate null pointer from empty string? */
37742 duk_debug_write_string(thr,
37743 (h != NULL ? (const char *) DUK_HSTRING_GET_DATA(h) : NULL),
37744 (h != NULL ? (duk_size_t) DUK_HSTRING_GET_BYTELEN(h) : 0));
37745}
37746
11fdf7f2
TL
37747DUK_LOCAL void duk__debug_write_hstring_safe_top(duk_hthread *thr) {
37748 duk_context *ctx = (duk_context *) thr;
37749 duk_debug_write_hstring(thr, duk_safe_to_hstring(ctx, -1));
37750}
37751
7c673cae 37752DUK_INTERNAL void duk_debug_write_buffer(duk_hthread *thr, const char *data, duk_size_t length) {
11fdf7f2 37753 duk_debug_write_strbuf(thr, data, length, DUK_DBG_IB_BUF4);
7c673cae
FG
37754}
37755
37756DUK_INTERNAL void duk_debug_write_hbuffer(duk_hthread *thr, duk_hbuffer *h) {
37757 DUK_ASSERT(thr != NULL);
37758
37759 duk_debug_write_buffer(thr,
37760 (h != NULL ? (const char *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h) : NULL),
37761 (h != NULL ? (duk_size_t) DUK_HBUFFER_GET_SIZE(h) : 0));
37762}
37763
11fdf7f2 37764DUK_LOCAL void duk__debug_write_pointer_raw(duk_hthread *thr, void *ptr, duk_uint8_t ibyte) {
7c673cae 37765 duk_uint8_t buf[2];
11fdf7f2 37766 duk__ptr_union pu;
7c673cae
FG
37767
37768 DUK_ASSERT(thr != NULL);
37769 DUK_ASSERT(sizeof(ptr) >= 1 && sizeof(ptr) <= 16);
37770 /* ptr may be NULL */
37771
37772 buf[0] = ibyte;
37773 buf[1] = sizeof(pu);
37774 duk_debug_write_bytes(thr, buf, 2);
37775 pu.p = (void *) ptr;
37776#if defined(DUK_USE_INTEGER_LE)
37777 duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu));
37778#endif
37779 duk_debug_write_bytes(thr, (const duk_uint8_t *) &pu.p, (duk_size_t) sizeof(pu));
37780}
37781
11fdf7f2
TL
37782DUK_INTERNAL void duk_debug_write_pointer(duk_hthread *thr, void *ptr) {
37783 duk__debug_write_pointer_raw(thr, ptr, DUK_DBG_IB_POINTER);
7c673cae
FG
37784}
37785
11fdf7f2 37786#if defined(DUK_USE_DEBUGGER_DUMPHEAP) || defined(DUK_USE_DEBUGGER_INSPECT)
7c673cae 37787DUK_INTERNAL void duk_debug_write_heapptr(duk_hthread *thr, duk_heaphdr *h) {
11fdf7f2 37788 duk__debug_write_pointer_raw(thr, (void *) h, DUK_DBG_IB_HEAPPTR);
7c673cae 37789}
11fdf7f2 37790#endif /* DUK_USE_DEBUGGER_DUMPHEAP || DUK_USE_DEBUGGER_INSPECT */
7c673cae
FG
37791
37792DUK_INTERNAL void duk_debug_write_hobject(duk_hthread *thr, duk_hobject *obj) {
37793 duk_uint8_t buf[3];
11fdf7f2 37794 duk__ptr_union pu;
7c673cae
FG
37795
37796 DUK_ASSERT(thr != NULL);
37797 DUK_ASSERT(sizeof(obj) >= 1 && sizeof(obj) <= 16);
37798 DUK_ASSERT(obj != NULL);
37799
11fdf7f2 37800 buf[0] = DUK_DBG_IB_OBJECT;
7c673cae
FG
37801 buf[1] = (duk_uint8_t) DUK_HOBJECT_GET_CLASS_NUMBER(obj);
37802 buf[2] = sizeof(pu);
37803 duk_debug_write_bytes(thr, buf, 3);
37804 pu.p = (void *) obj;
37805#if defined(DUK_USE_INTEGER_LE)
37806 duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu));
37807#endif
37808 duk_debug_write_bytes(thr, (const duk_uint8_t *) &pu.p, (duk_size_t) sizeof(pu));
37809}
37810
37811DUK_INTERNAL void duk_debug_write_tval(duk_hthread *thr, duk_tval *tv) {
37812 duk_c_function lf_func;
37813 duk_small_uint_t lf_flags;
37814 duk_uint8_t buf[4];
11fdf7f2
TL
37815 duk_double_union du1;
37816 duk_double_union du2;
37817 duk_int32_t i32;
7c673cae
FG
37818
37819 DUK_ASSERT(thr != NULL);
37820 DUK_ASSERT(tv != NULL);
37821
37822 switch (DUK_TVAL_GET_TAG(tv)) {
37823 case DUK_TAG_UNDEFINED:
11fdf7f2
TL
37824 duk_debug_write_byte(thr, DUK_DBG_IB_UNDEFINED);
37825 break;
37826 case DUK_TAG_UNUSED:
37827 duk_debug_write_byte(thr, DUK_DBG_IB_UNUSED);
7c673cae
FG
37828 break;
37829 case DUK_TAG_NULL:
11fdf7f2 37830 duk_debug_write_byte(thr, DUK_DBG_IB_NULL);
7c673cae
FG
37831 break;
37832 case DUK_TAG_BOOLEAN:
37833 DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv) == 0 ||
37834 DUK_TVAL_GET_BOOLEAN(tv) == 1);
11fdf7f2 37835 duk_debug_write_boolean(thr, DUK_TVAL_GET_BOOLEAN(tv));
7c673cae
FG
37836 break;
37837 case DUK_TAG_POINTER:
11fdf7f2 37838 duk_debug_write_pointer(thr, (void *) DUK_TVAL_GET_POINTER(tv));
7c673cae
FG
37839 break;
37840 case DUK_TAG_LIGHTFUNC:
37841 DUK_TVAL_GET_LIGHTFUNC(tv, lf_func, lf_flags);
11fdf7f2 37842 buf[0] = DUK_DBG_IB_LIGHTFUNC;
7c673cae
FG
37843 buf[1] = (duk_uint8_t) (lf_flags >> 8);
37844 buf[2] = (duk_uint8_t) (lf_flags & 0xff);
37845 buf[3] = sizeof(lf_func);
37846 duk_debug_write_bytes(thr, buf, 4);
37847 duk_debug_write_bytes(thr, (const duk_uint8_t *) &lf_func, sizeof(lf_func));
37848 break;
37849 case DUK_TAG_STRING:
37850 duk_debug_write_hstring(thr, DUK_TVAL_GET_STRING(tv));
37851 break;
37852 case DUK_TAG_OBJECT:
37853 duk_debug_write_hobject(thr, DUK_TVAL_GET_OBJECT(tv));
37854 break;
37855 case DUK_TAG_BUFFER:
37856 duk_debug_write_hbuffer(thr, DUK_TVAL_GET_BUFFER(tv));
37857 break;
37858#if defined(DUK_USE_FASTINT)
37859 case DUK_TAG_FASTINT:
37860#endif
37861 default:
11fdf7f2
TL
37862 /* Numbers are normalized to big (network) endian. We can
37863 * (but are not required) to use integer dvalues when there's
37864 * no loss of precision.
37865 *
37866 * XXX: share check with other code; this check is slow but
37867 * reliable and doesn't require careful exponent/mantissa
37868 * mask tricks as in the fastint downgrade code.
37869 */
37870 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
7c673cae 37871 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
11fdf7f2
TL
37872 du1.d = DUK_TVAL_GET_NUMBER(tv);
37873 i32 = (duk_int32_t) du1.d;
37874 du2.d = (duk_double_t) i32;
37875
37876 DUK_DD(DUK_DDPRINT("i32=%ld du1=%02x%02x%02x%02x%02x%02x%02x%02x "
37877 "du2=%02x%02x%02x%02x%02x%02x%02x%02x",
37878 (long) i32,
37879 (unsigned int) du1.uc[0], (unsigned int) du1.uc[1],
37880 (unsigned int) du1.uc[2], (unsigned int) du1.uc[3],
37881 (unsigned int) du1.uc[4], (unsigned int) du1.uc[5],
37882 (unsigned int) du1.uc[6], (unsigned int) du1.uc[7],
37883 (unsigned int) du2.uc[0], (unsigned int) du2.uc[1],
37884 (unsigned int) du2.uc[2], (unsigned int) du2.uc[3],
37885 (unsigned int) du2.uc[4], (unsigned int) du2.uc[5],
37886 (unsigned int) du2.uc[6], (unsigned int) du2.uc[7]));
37887
37888 if (DUK_MEMCMP((const void *) du1.uc, (const void *) du2.uc, sizeof(du1.uc)) == 0) {
37889 duk_debug_write_int(thr, i32);
37890 } else {
37891 DUK_DBLUNION_DOUBLE_HTON(&du1);
37892 duk_debug_write_byte(thr, DUK_DBG_IB_NUMBER);
37893 duk_debug_write_bytes(thr, (const duk_uint8_t *) du1.uc, sizeof(du1.uc));
37894 }
7c673cae
FG
37895 }
37896}
37897
37898#if defined(DUK_USE_DEBUGGER_DUMPHEAP)
37899/* Variant for writing duk_tvals so that any heap allocated values are
37900 * written out as tagged heap pointers.
37901 */
37902DUK_LOCAL void duk__debug_write_tval_heapptr(duk_hthread *thr, duk_tval *tv) {
37903 if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
37904 duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
37905 duk_debug_write_heapptr(thr, h);
37906 } else {
37907 duk_debug_write_tval(thr, tv);
37908 }
37909}
37910#endif /* DUK_USE_DEBUGGER_DUMPHEAP */
37911
37912/*
37913 * Debug connection message write helpers
37914 */
37915
37916#if 0 /* unused */
37917DUK_INTERNAL void duk_debug_write_request(duk_hthread *thr, duk_small_uint_t command) {
11fdf7f2 37918 duk_debug_write_byte(thr, DUK_DBG_IB_REQUEST);
7c673cae
FG
37919 duk_debug_write_int(thr, command);
37920}
37921#endif
37922
37923DUK_INTERNAL void duk_debug_write_reply(duk_hthread *thr) {
11fdf7f2 37924 duk_debug_write_byte(thr, DUK_DBG_IB_REPLY);
7c673cae
FG
37925}
37926
37927DUK_INTERNAL void duk_debug_write_error_eom(duk_hthread *thr, duk_small_uint_t err_code, const char *msg) {
37928 /* Allow NULL 'msg' */
11fdf7f2 37929 duk_debug_write_byte(thr, DUK_DBG_IB_ERROR);
7c673cae
FG
37930 duk_debug_write_int(thr, (duk_int32_t) err_code);
37931 duk_debug_write_cstring(thr, msg);
37932 duk_debug_write_eom(thr);
37933}
37934
37935DUK_INTERNAL void duk_debug_write_notify(duk_hthread *thr, duk_small_uint_t command) {
11fdf7f2 37936 duk_debug_write_byte(thr, DUK_DBG_IB_NOTIFY);
7c673cae
FG
37937 duk_debug_write_int(thr, command);
37938}
37939
37940DUK_INTERNAL void duk_debug_write_eom(duk_hthread *thr) {
11fdf7f2 37941 duk_debug_write_byte(thr, DUK_DBG_IB_EOM);
7c673cae
FG
37942
37943 /* As an initial implementation, write flush after every EOM (and the
37944 * version identifier). A better implementation would flush only when
37945 * Duktape is finished processing messages so that a flush only happens
37946 * after all outbound messages are finished on that occasion.
37947 */
37948 duk_debug_write_flush(thr);
37949}
37950
37951/*
37952 * Status message and helpers
37953 */
37954
37955DUK_INTERNAL duk_uint_fast32_t duk_debug_curr_line(duk_hthread *thr) {
37956 duk_context *ctx = (duk_context *) thr;
37957 duk_activation *act;
37958 duk_uint_fast32_t line;
37959 duk_uint_fast32_t pc;
37960
11fdf7f2
TL
37961 act = duk_hthread_get_current_activation(thr); /* may be NULL */
37962 if (act == NULL) {
7c673cae
FG
37963 return 0;
37964 }
7c673cae
FG
37965
37966 /* We're conceptually between two opcodes; act->pc indicates the next
37967 * instruction to be executed. This is usually the correct pc/line to
37968 * indicate in Status. (For the 'debugger' statement this now reports
37969 * the pc/line after the debugger statement because the debugger opcode
37970 * has already been executed.)
37971 */
37972
37973 pc = duk_hthread_get_act_curr_pc(thr, act);
37974
37975 /* XXX: this should be optimized to be a raw query and avoid valstack
37976 * operations if possible.
37977 */
11fdf7f2 37978 duk_push_tval(ctx, &act->tv_func);
7c673cae
FG
37979 line = duk_hobject_pc2line_query(ctx, -1, pc);
37980 duk_pop(ctx);
37981 return line;
37982}
37983
37984DUK_INTERNAL void duk_debug_send_status(duk_hthread *thr) {
37985 duk_context *ctx = (duk_context *) thr;
37986 duk_activation *act;
37987
37988 duk_debug_write_notify(thr, DUK_DBG_CMD_STATUS);
37989 duk_debug_write_int(thr, thr->heap->dbg_paused);
37990
37991 DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* unsigned */
37992 if (thr->callstack_top == 0) {
37993 duk_debug_write_undefined(thr);
37994 duk_debug_write_undefined(thr);
37995 duk_debug_write_int(thr, 0);
37996 duk_debug_write_int(thr, 0);
37997 } else {
37998 act = thr->callstack + thr->callstack_top - 1;
11fdf7f2 37999 duk_push_tval(ctx, &act->tv_func);
7c673cae 38000 duk_get_prop_string(ctx, -1, "fileName");
11fdf7f2 38001 duk__debug_write_hstring_safe_top(thr);
7c673cae 38002 duk_get_prop_string(ctx, -2, "name");
11fdf7f2 38003 duk__debug_write_hstring_safe_top(thr);
7c673cae
FG
38004 duk_pop_3(ctx);
38005 /* Report next pc/line to be executed. */
38006 duk_debug_write_uint(thr, (duk_uint32_t) duk_debug_curr_line(thr));
11fdf7f2 38007 act = thr->callstack + thr->callstack_top - 1;
7c673cae
FG
38008 duk_debug_write_uint(thr, (duk_uint32_t) duk_hthread_get_act_curr_pc(thr, act));
38009 }
38010
38011 duk_debug_write_eom(thr);
38012}
38013
11fdf7f2
TL
38014#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY)
38015DUK_INTERNAL void duk_debug_send_throw(duk_hthread *thr, duk_bool_t fatal) {
38016 /*
38017 * NFY <int: 5> <int: fatal> <str: msg> <str: filename> <int: linenumber> EOM
38018 */
38019
38020 duk_context *ctx = (duk_context *) thr;
38021 duk_activation *act;
38022 duk_uint32_t pc;
38023
38024 DUK_ASSERT(thr->valstack_top > thr->valstack); /* At least: ... [err] */
38025
38026 duk_debug_write_notify(thr, DUK_DBG_CMD_THROW);
38027 duk_debug_write_int(thr, fatal);
38028
38029 /* Report thrown value to client coerced to string */
38030 duk_dup(ctx, -1);
38031 duk__debug_write_hstring_safe_top(thr);
38032 duk_pop(ctx);
38033
38034 if (duk_is_error(ctx, -1)) {
38035 /* Error instance, use augmented error data directly */
38036 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_FILE_NAME);
38037 duk__debug_write_hstring_safe_top(thr);
38038 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_LINE_NUMBER);
38039 duk_debug_write_uint(thr, duk_get_uint(ctx, -1));
38040 duk_pop_2(ctx);
38041 } else {
38042 /* For anything other than an Error instance, we calculate the
38043 * error location directly from the current activation if one
38044 * exists.
38045 */
38046 if (thr->callstack_top > 0) {
38047 act = thr->callstack + thr->callstack_top - 1;
38048 duk_push_tval(ctx, &act->tv_func);
38049 duk_get_prop_string(ctx, -1, "fileName");
38050 duk__debug_write_hstring_safe_top(thr);
38051 act = thr->callstack + thr->callstack_top - 1;
38052 pc = duk_hthread_get_act_prev_pc(thr, act);
38053 duk_debug_write_uint(thr, (duk_uint32_t) duk_hobject_pc2line_query(ctx, -2, pc));
38054 duk_pop_2(ctx);
38055 } else {
38056 /* Can happen if duk_throw() is called on an empty
38057 * callstack.
38058 */
38059 duk_debug_write_cstring(thr, "");
38060 duk_debug_write_uint(thr, 0);
38061 }
38062 }
38063
38064 duk_debug_write_eom(thr);
38065}
38066#endif /* DUK_USE_DEBUGGER_THROW_NOTIFY */
38067
7c673cae
FG
38068/*
38069 * Debug message processing
38070 */
38071
38072/* Skip dvalue. */
38073DUK_LOCAL duk_bool_t duk__debug_skip_dvalue(duk_hthread *thr) {
38074 duk_uint8_t x;
38075 duk_uint32_t len;
38076
38077 x = duk_debug_read_byte(thr);
38078
38079 if (x >= 0xc0) {
38080 duk_debug_skip_byte(thr);
38081 return 0;
38082 }
38083 if (x >= 0x80) {
38084 return 0;
38085 }
38086 if (x >= 0x60) {
38087 duk_debug_skip_bytes(thr, x - 0x60);
38088 return 0;
38089 }
38090 switch(x) {
11fdf7f2 38091 case DUK_DBG_IB_EOM:
7c673cae 38092 return 1; /* Return 1: got EOM */
11fdf7f2
TL
38093 case DUK_DBG_IB_REQUEST:
38094 case DUK_DBG_IB_REPLY:
38095 case DUK_DBG_IB_ERROR:
38096 case DUK_DBG_IB_NOTIFY:
7c673cae 38097 break;
11fdf7f2 38098 case DUK_DBG_IB_INT4:
7c673cae
FG
38099 (void) duk__debug_read_uint32_raw(thr);
38100 break;
11fdf7f2
TL
38101 case DUK_DBG_IB_STR4:
38102 case DUK_DBG_IB_BUF4:
7c673cae
FG
38103 len = duk__debug_read_uint32_raw(thr);
38104 duk_debug_skip_bytes(thr, len);
38105 break;
11fdf7f2
TL
38106 case DUK_DBG_IB_STR2:
38107 case DUK_DBG_IB_BUF2:
7c673cae
FG
38108 len = duk__debug_read_uint16_raw(thr);
38109 duk_debug_skip_bytes(thr, len);
38110 break;
11fdf7f2
TL
38111 case DUK_DBG_IB_UNUSED:
38112 case DUK_DBG_IB_UNDEFINED:
38113 case DUK_DBG_IB_NULL:
38114 case DUK_DBG_IB_TRUE:
38115 case DUK_DBG_IB_FALSE:
7c673cae 38116 break;
11fdf7f2 38117 case DUK_DBG_IB_NUMBER:
7c673cae
FG
38118 duk_debug_skip_bytes(thr, 8);
38119 break;
11fdf7f2 38120 case DUK_DBG_IB_OBJECT:
7c673cae
FG
38121 duk_debug_skip_byte(thr);
38122 len = duk_debug_read_byte(thr);
38123 duk_debug_skip_bytes(thr, len);
38124 break;
11fdf7f2
TL
38125 case DUK_DBG_IB_POINTER:
38126 case DUK_DBG_IB_HEAPPTR:
7c673cae
FG
38127 len = duk_debug_read_byte(thr);
38128 duk_debug_skip_bytes(thr, len);
38129 break;
11fdf7f2 38130 case DUK_DBG_IB_LIGHTFUNC:
7c673cae
FG
38131 duk_debug_skip_bytes(thr, 2);
38132 len = duk_debug_read_byte(thr);
38133 duk_debug_skip_bytes(thr, len);
38134 break;
38135 default:
38136 goto fail;
38137 }
38138
38139 return 0;
38140
38141 fail:
11fdf7f2 38142 DUK__SET_CONN_BROKEN(thr, 1);
7c673cae
FG
38143 return 1; /* Pretend like we got EOM */
38144}
38145
38146/* Skip dvalues to EOM. */
38147DUK_LOCAL void duk__debug_skip_to_eom(duk_hthread *thr) {
38148 for (;;) {
38149 if (duk__debug_skip_dvalue(thr)) {
38150 break;
38151 }
38152 }
38153}
38154
38155/*
11fdf7f2 38156 * Simple commands
7c673cae
FG
38157 */
38158
38159DUK_LOCAL void duk__debug_handle_basic_info(duk_hthread *thr, duk_heap *heap) {
38160 DUK_UNREF(heap);
11fdf7f2 38161 DUK_D(DUK_DPRINT("debug command Version"));
7c673cae
FG
38162
38163 duk_debug_write_reply(thr);
38164 duk_debug_write_int(thr, DUK_VERSION);
38165 duk_debug_write_cstring(thr, DUK_GIT_DESCRIBE);
38166 duk_debug_write_cstring(thr, DUK_USE_TARGET_INFO);
38167#if defined(DUK_USE_DOUBLE_LE)
38168 duk_debug_write_int(thr, 1);
38169#elif defined(DUK_USE_DOUBLE_ME)
38170 duk_debug_write_int(thr, 2);
38171#elif defined(DUK_USE_DOUBLE_BE)
38172 duk_debug_write_int(thr, 3);
38173#else
38174 duk_debug_write_int(thr, 0);
38175#endif
11fdf7f2 38176 duk_debug_write_int(thr, (duk_int_t) sizeof(void *));
7c673cae
FG
38177 duk_debug_write_eom(thr);
38178}
38179
38180DUK_LOCAL void duk__debug_handle_trigger_status(duk_hthread *thr, duk_heap *heap) {
38181 DUK_UNREF(heap);
11fdf7f2 38182 DUK_D(DUK_DPRINT("debug command TriggerStatus"));
7c673cae
FG
38183
38184 duk_debug_write_reply(thr);
38185 duk_debug_write_eom(thr);
38186 heap->dbg_state_dirty = 1;
38187}
38188
38189DUK_LOCAL void duk__debug_handle_pause(duk_hthread *thr, duk_heap *heap) {
11fdf7f2 38190 DUK_D(DUK_DPRINT("debug command Pause"));
7c673cae
FG
38191
38192 DUK_HEAP_SET_PAUSED(heap);
38193 duk_debug_write_reply(thr);
38194 duk_debug_write_eom(thr);
38195}
38196
38197DUK_LOCAL void duk__debug_handle_resume(duk_hthread *thr, duk_heap *heap) {
11fdf7f2 38198 DUK_D(DUK_DPRINT("debug command Resume"));
7c673cae
FG
38199
38200 DUK_HEAP_CLEAR_PAUSED(heap);
38201 duk_debug_write_reply(thr);
38202 duk_debug_write_eom(thr);
38203}
38204
38205DUK_LOCAL void duk__debug_handle_step(duk_hthread *thr, duk_heap *heap, duk_int32_t cmd) {
38206 duk_small_uint_t step_type;
38207 duk_uint_fast32_t line;
38208
11fdf7f2
TL
38209 DUK_D(DUK_DPRINT("debug command StepInto/StepOver/StepOut: %d", (int) cmd));
38210
7c673cae
FG
38211 if (cmd == DUK_DBG_CMD_STEPINTO) {
38212 step_type = DUK_STEP_TYPE_INTO;
38213 } else if (cmd == DUK_DBG_CMD_STEPOVER) {
38214 step_type = DUK_STEP_TYPE_OVER;
38215 } else {
38216 DUK_ASSERT(cmd == DUK_DBG_CMD_STEPOUT);
38217 step_type = DUK_STEP_TYPE_OUT;
38218 }
38219
7c673cae
FG
38220 line = duk_debug_curr_line(thr);
38221 if (line > 0) {
38222 heap->dbg_paused = 0;
38223 heap->dbg_step_type = step_type;
38224 heap->dbg_step_thread = thr;
38225 heap->dbg_step_csindex = thr->callstack_top - 1;
38226 heap->dbg_step_startline = line;
38227 heap->dbg_state_dirty = 1;
38228 } else {
38229 DUK_D(DUK_DPRINT("cannot determine current line, stepinto/stepover/stepout ignored"));
38230 }
38231 duk_debug_write_reply(thr);
38232 duk_debug_write_eom(thr);
38233}
38234
38235DUK_LOCAL void duk__debug_handle_list_break(duk_hthread *thr, duk_heap *heap) {
38236 duk_small_int_t i;
38237
11fdf7f2 38238 DUK_D(DUK_DPRINT("debug command ListBreak"));
7c673cae
FG
38239 duk_debug_write_reply(thr);
38240 for (i = 0; i < (duk_small_int_t) heap->dbg_breakpoint_count; i++) {
38241 duk_debug_write_hstring(thr, heap->dbg_breakpoints[i].filename);
38242 duk_debug_write_uint(thr, (duk_uint32_t) heap->dbg_breakpoints[i].line);
38243 }
38244 duk_debug_write_eom(thr);
38245}
38246
38247DUK_LOCAL void duk__debug_handle_add_break(duk_hthread *thr, duk_heap *heap) {
7c673cae
FG
38248 duk_hstring *filename;
38249 duk_uint32_t linenumber;
38250 duk_small_int_t idx;
38251
38252 DUK_UNREF(heap);
38253
38254 filename = duk_debug_read_hstring(thr);
38255 linenumber = (duk_uint32_t) duk_debug_read_int(thr);
11fdf7f2 38256 DUK_D(DUK_DPRINT("debug command AddBreak: %!O:%ld", (duk_hobject *) filename, (long) linenumber));
7c673cae
FG
38257 idx = duk_debug_add_breakpoint(thr, filename, linenumber);
38258 if (idx >= 0) {
38259 duk_debug_write_reply(thr);
38260 duk_debug_write_int(thr, (duk_int32_t) idx);
38261 duk_debug_write_eom(thr);
38262 } else {
38263 duk_debug_write_error_eom(thr, DUK_DBG_ERR_TOOMANY, "no space for breakpoint");
38264 }
7c673cae
FG
38265}
38266
38267DUK_LOCAL void duk__debug_handle_del_break(duk_hthread *thr, duk_heap *heap) {
38268 duk_small_uint_t idx;
38269
38270 DUK_UNREF(heap);
38271
11fdf7f2 38272 DUK_D(DUK_DPRINT("debug command DelBreak"));
7c673cae
FG
38273 idx = (duk_small_uint_t) duk_debug_read_int(thr);
38274 if (duk_debug_remove_breakpoint(thr, idx)) {
38275 duk_debug_write_reply(thr);
38276 duk_debug_write_eom(thr);
38277 } else {
38278 duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid breakpoint index");
38279 }
38280}
38281
38282DUK_LOCAL void duk__debug_handle_get_var(duk_hthread *thr, duk_heap *heap) {
38283 duk_context *ctx = (duk_context *) thr;
38284 duk_hstring *str;
38285 duk_bool_t rc;
11fdf7f2 38286 duk_int32_t level;
7c673cae
FG
38287
38288 DUK_UNREF(heap);
11fdf7f2 38289 DUK_D(DUK_DPRINT("debug command GetVar"));
7c673cae
FG
38290
38291 str = duk_debug_read_hstring(thr); /* push to stack */
38292 DUK_ASSERT(str != NULL);
11fdf7f2
TL
38293 if (duk_debug_peek_byte(thr) != DUK_DBG_IB_EOM) {
38294 level = duk_debug_read_int(thr); /* optional callstack level */
38295 if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
38296 DUK_D(DUK_DPRINT("invalid callstack level for GetVar"));
38297 duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack level");
38298 return;
38299 }
38300 } else {
38301 level = -1;
38302 }
7c673cae
FG
38303
38304 if (thr->callstack_top > 0) {
38305 rc = duk_js_getvar_activation(thr,
11fdf7f2 38306 thr->callstack + thr->callstack_top + level,
7c673cae
FG
38307 str,
38308 0);
38309 } else {
38310 /* No activation, no variable access. Could also pretend
38311 * we're in the global program context and read stuff off
38312 * the global object.
38313 */
38314 DUK_D(DUK_DPRINT("callstack empty, no activation -> ignore getvar"));
38315 rc = 0;
38316 }
38317
38318 duk_debug_write_reply(thr);
38319 if (rc) {
38320 duk_debug_write_int(thr, 1);
11fdf7f2
TL
38321 DUK_ASSERT(duk_get_tval(ctx, -2) != NULL);
38322 duk_debug_write_tval(thr, duk_get_tval(ctx, -2));
7c673cae
FG
38323 } else {
38324 duk_debug_write_int(thr, 0);
38325 duk_debug_write_unused(thr);
38326 }
7c673cae
FG
38327 duk_debug_write_eom(thr);
38328}
38329
38330DUK_LOCAL void duk__debug_handle_put_var(duk_hthread *thr, duk_heap *heap) {
7c673cae
FG
38331 duk_hstring *str;
38332 duk_tval *tv;
11fdf7f2 38333 duk_int32_t level;
7c673cae
FG
38334
38335 DUK_UNREF(heap);
11fdf7f2 38336 DUK_D(DUK_DPRINT("debug command PutVar"));
7c673cae
FG
38337
38338 str = duk_debug_read_hstring(thr); /* push to stack */
38339 DUK_ASSERT(str != NULL);
11fdf7f2
TL
38340 tv = duk_debug_read_tval(thr);
38341 if (tv == NULL) {
38342 /* detached */
38343 return;
38344 }
38345 if (duk_debug_peek_byte(thr) != DUK_DBG_IB_EOM) {
38346 level = duk_debug_read_int(thr); /* optional callstack level */
38347 if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
38348 DUK_D(DUK_DPRINT("invalid callstack level for PutVar"));
38349 duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack level");
38350 return;
38351 }
38352 } else {
38353 level = -1;
38354 }
7c673cae
FG
38355
38356 if (thr->callstack_top > 0) {
38357 duk_js_putvar_activation(thr,
11fdf7f2 38358 thr->callstack + thr->callstack_top + level,
7c673cae
FG
38359 str,
38360 tv,
38361 0);
38362 } else {
38363 DUK_D(DUK_DPRINT("callstack empty, no activation -> ignore putvar"));
38364 }
7c673cae
FG
38365
38366 /* XXX: Current putvar implementation doesn't have a success flag,
38367 * add one and send to debug client?
38368 */
38369 duk_debug_write_reply(thr);
38370 duk_debug_write_eom(thr);
38371}
38372
38373DUK_LOCAL void duk__debug_handle_get_call_stack(duk_hthread *thr, duk_heap *heap) {
38374 duk_context *ctx = (duk_context *) thr;
38375 duk_hthread *curr_thr = thr;
38376 duk_activation *curr_act;
38377 duk_uint_fast32_t pc;
38378 duk_uint_fast32_t line;
38379 duk_size_t i;
38380
11fdf7f2 38381 DUK_ASSERT(thr != NULL);
7c673cae
FG
38382 DUK_UNREF(heap);
38383
38384 duk_debug_write_reply(thr);
38385 while (curr_thr != NULL) {
38386 i = curr_thr->callstack_top;
38387 while (i > 0) {
38388 i--;
38389 curr_act = curr_thr->callstack + i;
38390
38391 /* PC/line semantics here are:
38392 * - For callstack top we're conceptually between two
38393 * opcodes and current PC indicates next line to
38394 * execute, so report that (matches Status).
38395 * - For other activations we're conceptually still
38396 * executing the instruction at PC-1, so report that
38397 * (matches error stacktrace behavior).
38398 * - See: https://github.com/svaarala/duktape/issues/281
38399 */
38400
38401 /* XXX: optimize to use direct reads, i.e. avoid
38402 * value stack operations.
38403 */
38404 duk_push_tval(ctx, &curr_act->tv_func);
38405 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_FILE_NAME);
11fdf7f2 38406 duk__debug_write_hstring_safe_top(thr);
7c673cae 38407 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME);
11fdf7f2 38408 duk__debug_write_hstring_safe_top(thr);
7c673cae
FG
38409 pc = duk_hthread_get_act_curr_pc(thr, curr_act);
38410 if (i != curr_thr->callstack_top - 1 && pc > 0) {
38411 pc--;
38412 }
38413 line = duk_hobject_pc2line_query(ctx, -3, pc);
38414 duk_debug_write_uint(thr, (duk_uint32_t) line);
38415 duk_debug_write_uint(thr, (duk_uint32_t) pc);
38416 duk_pop_3(ctx);
38417 }
38418 curr_thr = curr_thr->resumer;
38419 }
11fdf7f2
TL
38420 /* SCANBUILD: warning about 'thr' potentially being NULL here,
38421 * warning is incorrect because thr != NULL always here.
38422 */
7c673cae
FG
38423 duk_debug_write_eom(thr);
38424}
38425
38426DUK_LOCAL void duk__debug_handle_get_locals(duk_hthread *thr, duk_heap *heap) {
38427 duk_context *ctx = (duk_context *) thr;
38428 duk_activation *curr_act;
11fdf7f2 38429 duk_int32_t level;
7c673cae
FG
38430 duk_hstring *varname;
38431
38432 DUK_UNREF(heap);
38433
11fdf7f2
TL
38434 if (duk_debug_peek_byte(thr) != DUK_DBG_IB_EOM) {
38435 level = duk_debug_read_int(thr); /* optional callstack level */
38436 if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
38437 DUK_D(DUK_DPRINT("invalid callstack level for GetLocals"));
38438 duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack level");
38439 return;
38440 }
38441 duk_debug_write_reply(thr);
38442 } else {
38443 duk_debug_write_reply(thr);
38444 if (thr->callstack_top == 0) {
38445 goto callstack_empty;
38446 }
38447 level = -1;
7c673cae 38448 }
11fdf7f2
TL
38449
38450 curr_act = thr->callstack + thr->callstack_top + level;
7c673cae
FG
38451
38452 /* XXX: several nice-to-have improvements here:
38453 * - Use direct reads avoiding value stack operations
38454 * - Avoid triggering getters, indicate getter values to debug client
38455 * - If side effects are possible, add error catching
38456 */
38457
38458 duk_push_tval(ctx, &curr_act->tv_func);
38459 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VARMAP);
38460 if (duk_is_object(ctx, -1)) {
38461 duk_enum(ctx, -1, 0 /*enum_flags*/);
38462 while (duk_next(ctx, -1 /*enum_index*/, 0 /*get_value*/)) {
38463 varname = duk_get_hstring(ctx, -1);
38464 DUK_ASSERT(varname != NULL);
38465
38466 duk_js_getvar_activation(thr, curr_act, varname, 0 /*throw_flag*/);
38467 /* [ ... func varmap enum key value this ] */
38468 duk_debug_write_hstring(thr, duk_get_hstring(ctx, -3));
38469 duk_debug_write_tval(thr, duk_get_tval(ctx, -2));
38470 duk_pop_3(ctx); /* -> [ ... func varmap enum ] */
38471 }
7c673cae
FG
38472 } else {
38473 DUK_D(DUK_DPRINT("varmap is not an object in GetLocals, ignore"));
38474 }
7c673cae
FG
38475
38476 callstack_empty:
38477 duk_debug_write_eom(thr);
38478}
38479
38480DUK_LOCAL void duk__debug_handle_eval(duk_hthread *thr, duk_heap *heap) {
38481 duk_context *ctx = (duk_context *) thr;
7c673cae
FG
38482 duk_small_uint_t call_flags;
38483 duk_int_t call_ret;
38484 duk_small_int_t eval_err;
11fdf7f2 38485 duk_int32_t level;
7c673cae
FG
38486
38487 DUK_UNREF(heap);
38488
11fdf7f2 38489 DUK_D(DUK_DPRINT("debug command Eval"));
7c673cae 38490
11fdf7f2
TL
38491 /* The eval code is executed within the lexical environment of a specified
38492 * activation. For now, use global object eval() function, with the eval
38493 * considered a 'direct call to eval'.
38494 *
38495 * Callstack level for debug commands only affects scope -- the callstack
38496 * as seen by, e.g. Duktape.act() will be the same regardless.
7c673cae
FG
38497 */
38498
11fdf7f2
TL
38499 /* nargs == 2 so we can pass a callstack level to eval(). */
38500 duk_push_c_function(ctx, duk_bi_global_object_eval, 2 /*nargs*/);
7c673cae 38501 duk_push_undefined(ctx); /* 'this' binding shouldn't matter here */
11fdf7f2 38502
7c673cae 38503 (void) duk_debug_read_hstring(thr);
11fdf7f2
TL
38504 if (duk_debug_peek_byte(thr) != DUK_DBG_IB_EOM) {
38505 level = duk_debug_read_int(thr); /* optional callstack level */
38506 if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
38507 DUK_D(DUK_DPRINT("invalid callstack level for Eval"));
38508 duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack level");
38509 return;
38510 }
38511 }
38512 else {
38513 level = -1;
38514 }
38515 DUK_ASSERT(level < 0 && -level <= (duk_int32_t) thr->callstack_top);
38516 duk_push_int(ctx, level - 1); /* compensate for eval() call */
7c673cae 38517
11fdf7f2 38518 /* [ ... eval "eval" eval_input level ] */
7c673cae 38519
11fdf7f2
TL
38520 call_flags = 0;
38521 if (thr->callstack_top >= (duk_size_t) -level) {
7c673cae
FG
38522 duk_activation *act;
38523 duk_hobject *fun;
38524
11fdf7f2 38525 act = thr->callstack + thr->callstack_top + level;
7c673cae 38526 fun = DUK_ACT_GET_FUNC(act);
11fdf7f2 38527 if (fun != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION(fun)) {
7c673cae
FG
38528 /* Direct eval requires that there's a current
38529 * activation and it is an Ecmascript function.
38530 * When Eval is executed from e.g. cooperate API
11fdf7f2 38531 * call we'll need to do an indirect eval instead.
7c673cae
FG
38532 */
38533 call_flags |= DUK_CALL_FLAG_DIRECT_EVAL;
38534 }
38535 }
38536
11fdf7f2 38537 call_ret = duk_handle_call_protected(thr, 2 /*num_stack_args*/, call_flags);
7c673cae
FG
38538
38539 if (call_ret == DUK_EXEC_SUCCESS) {
38540 eval_err = 0;
38541 /* Use result value as is. */
38542 } else {
38543 /* For errors a string coerced result is most informative
38544 * right now, as the debug client doesn't have the capability
38545 * to traverse the error object.
38546 */
38547 eval_err = 1;
38548 duk_safe_to_string(ctx, -1);
38549 }
38550
38551 /* [ ... result ] */
38552
38553 duk_debug_write_reply(thr);
38554 duk_debug_write_int(thr, (duk_int32_t) eval_err);
11fdf7f2
TL
38555 DUK_ASSERT(duk_get_tval(ctx, -1) != NULL);
38556 duk_debug_write_tval(thr, duk_get_tval(ctx, -1));
7c673cae 38557 duk_debug_write_eom(thr);
7c673cae
FG
38558}
38559
38560DUK_LOCAL void duk__debug_handle_detach(duk_hthread *thr, duk_heap *heap) {
38561 DUK_UNREF(heap);
11fdf7f2 38562 DUK_D(DUK_DPRINT("debug command Detach"));
7c673cae
FG
38563
38564 duk_debug_write_reply(thr);
38565 duk_debug_write_eom(thr);
38566
38567 DUK_D(DUK_DPRINT("debug connection detached, mark broken"));
11fdf7f2 38568 DUK__SET_CONN_BROKEN(thr, 0); /* not an error */
7c673cae
FG
38569}
38570
11fdf7f2
TL
38571DUK_LOCAL void duk__debug_handle_apprequest(duk_hthread *thr, duk_heap *heap) {
38572 duk_context *ctx = (duk_context *) thr;
38573 duk_idx_t old_top;
38574
38575 DUK_D(DUK_DPRINT("debug command AppRequest"));
38576
38577 old_top = duk_get_top(ctx); /* save stack top */
38578
38579 if (heap->dbg_request_cb != NULL) {
38580 duk_idx_t nrets;
38581 duk_idx_t nvalues = 0;
38582 duk_idx_t top, idx;
38583
38584 /* Read tvals from the message and push them onto the valstack,
38585 * then call the request callback to process the request.
38586 */
38587 while (duk_debug_peek_byte(thr) != DUK_DBG_IB_EOM) {
38588 duk_tval *tv;
38589 if (!duk_check_stack(ctx, 1)) {
38590 DUK_D(DUK_DPRINT("failed to allocate space for request dvalue(s)"));
38591 goto fail;
38592 }
38593 tv = duk_debug_read_tval(thr); /* push to stack */
38594 if (tv == NULL) {
38595 /* detached */
38596 return;
38597 }
38598 nvalues++;
38599 }
38600 DUK_ASSERT(duk_get_top(ctx) == old_top + nvalues);
38601
38602 /* Request callback should push values for reply to client onto valstack */
38603 DUK_D(DUK_DPRINT("calling into AppRequest request_cb with nvalues=%ld, old_top=%ld, top=%ld",
38604 (long) nvalues, (long) old_top, (long) duk_get_top(ctx)));
38605 nrets = heap->dbg_request_cb(ctx, heap->dbg_udata, nvalues);
38606 DUK_D(DUK_DPRINT("returned from AppRequest request_cb; nvalues=%ld -> nrets=%ld, old_top=%ld, top=%ld",
38607 (long) nvalues, (long) nrets, (long) old_top, (long) duk_get_top(ctx)));
38608 if (nrets >= 0) {
38609 DUK_ASSERT(duk_get_top(ctx) >= old_top + nrets);
38610 if (duk_get_top(ctx) < old_top + nrets) {
38611 DUK_D(DUK_DPRINT("AppRequest callback doesn't match value stack configuration, "
38612 "top=%ld < old_top=%ld + nrets=%ld; "
38613 "this might mean it's unsafe to continue!",
38614 (long) duk_get_top(ctx), (long) old_top, (long) nrets));
38615 goto fail;
38616 }
38617
38618 /* Reply with tvals pushed by request callback */
38619 duk_debug_write_byte(thr, DUK_DBG_IB_REPLY);
38620 top = duk_get_top(ctx);
38621 for (idx = top - nrets; idx < top; idx++) {
38622 duk_debug_write_tval(thr, DUK_GET_TVAL_POSIDX(ctx, idx));
38623 }
38624 duk_debug_write_eom(thr);
38625 } else {
38626 DUK_ASSERT(duk_get_top(ctx) >= old_top + 1);
38627 if (duk_get_top(ctx) < old_top + 1) {
38628 DUK_D(DUK_DPRINT("request callback return value doesn't match value stack configuration"));
38629 goto fail;
38630 }
38631 duk_debug_write_error_eom(thr, DUK_DBG_ERR_APPLICATION, duk_get_string(ctx, -1));
38632 }
38633
38634 duk_set_top(ctx, old_top); /* restore stack top */
38635 } else {
38636 DUK_D(DUK_DPRINT("no request callback, treat AppRequest as unsupported"));
38637 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNSUPPORTED, "AppRequest unsupported by target");
38638 }
38639
38640 return;
38641
38642 fail:
38643 duk_set_top(ctx, old_top); /* restore stack top */
38644 DUK__SET_CONN_BROKEN(thr, 1);
38645}
38646
38647/*
38648 * DumpHeap command
38649 */
38650
7c673cae 38651#if defined(DUK_USE_DEBUGGER_DUMPHEAP)
11fdf7f2
TL
38652/* XXX: this has some overlap with object inspection; remove this and make
38653 * DumpHeap return lists of heapptrs instead?
38654 */
7c673cae
FG
38655DUK_LOCAL void duk__debug_dump_heaphdr(duk_hthread *thr, duk_heap *heap, duk_heaphdr *hdr) {
38656 DUK_UNREF(heap);
38657
38658 duk_debug_write_heapptr(thr, hdr);
38659 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HEAPHDR_GET_TYPE(hdr));
38660 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HEAPHDR_GET_FLAGS_RAW(hdr));
38661#if defined(DUK_USE_REFERENCE_COUNTING)
38662 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HEAPHDR_GET_REFCOUNT(hdr));
38663#else
38664 duk_debug_write_int(thr, (duk_int32_t) -1);
38665#endif
38666
38667 switch (DUK_HEAPHDR_GET_TYPE(hdr)) {
38668 case DUK_HTYPE_STRING: {
38669 duk_hstring *h = (duk_hstring *) hdr;
38670
38671 duk_debug_write_uint(thr, (duk_int32_t) DUK_HSTRING_GET_BYTELEN(h));
38672 duk_debug_write_uint(thr, (duk_int32_t) DUK_HSTRING_GET_CHARLEN(h));
38673 duk_debug_write_uint(thr, (duk_int32_t) DUK_HSTRING_GET_HASH(h));
38674 duk_debug_write_hstring(thr, h);
38675 break;
38676 }
38677 case DUK_HTYPE_OBJECT: {
38678 duk_hobject *h = (duk_hobject *) hdr;
38679 duk_hstring *k;
38680 duk_uint_fast32_t i;
38681
38682 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_CLASS_NUMBER(h));
38683 duk_debug_write_heapptr(thr, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(heap, h));
38684 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_ESIZE(h));
38685 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_ENEXT(h));
38686 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_ASIZE(h));
38687 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_HSIZE(h));
38688
38689 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) {
38690 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_E_GET_FLAGS(heap, h, i));
38691 k = DUK_HOBJECT_E_GET_KEY(heap, h, i);
38692 duk_debug_write_heapptr(thr, (duk_heaphdr *) k);
38693 if (k == NULL) {
38694 duk_debug_write_int(thr, 0); /* isAccessor */
38695 duk_debug_write_unused(thr);
38696 continue;
38697 }
38698 if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, h, i)) {
38699 duk_debug_write_int(thr, 1); /* isAccessor */
38700 duk_debug_write_heapptr(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.get);
38701 duk_debug_write_heapptr(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.set);
38702 } else {
38703 duk_debug_write_int(thr, 0); /* isAccessor */
38704
38705 duk__debug_write_tval_heapptr(thr, &DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->v);
38706 }
38707 }
38708
38709 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) {
38710 /* Note: array dump will include elements beyond
38711 * 'length'.
38712 */
38713 duk__debug_write_tval_heapptr(thr, DUK_HOBJECT_A_GET_VALUE_PTR(heap, h, i));
38714 }
38715 break;
38716 }
38717 case DUK_HTYPE_BUFFER: {
38718 duk_hbuffer *h = (duk_hbuffer *) hdr;
38719
38720 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HBUFFER_GET_SIZE(h));
38721 duk_debug_write_buffer(thr, (const char *) DUK_HBUFFER_GET_DATA_PTR(heap, h), (duk_size_t) DUK_HBUFFER_GET_SIZE(h));
38722 break;
38723 }
38724 default: {
38725 DUK_D(DUK_DPRINT("invalid htype: %d", (int) DUK_HEAPHDR_GET_TYPE(hdr)));
38726 }
38727 }
38728}
38729
38730DUK_LOCAL void duk__debug_dump_heap_allocated(duk_hthread *thr, duk_heap *heap) {
38731 duk_heaphdr *hdr;
38732
38733 hdr = heap->heap_allocated;
38734 while (hdr != NULL) {
38735 duk__debug_dump_heaphdr(thr, heap, hdr);
38736 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
38737 }
38738}
38739
38740#if defined(DUK_USE_STRTAB_CHAIN)
38741DUK_LOCAL void duk__debug_dump_strtab_chain(duk_hthread *thr, duk_heap *heap) {
38742 duk_uint_fast32_t i, j;
38743 duk_strtab_entry *e;
38744#if defined(DUK_USE_HEAPPTR16)
38745 duk_uint16_t *lst;
38746#else
38747 duk_hstring **lst;
38748#endif
38749 duk_hstring *h;
38750
38751 for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
38752 e = heap->strtable + i;
38753 if (e->listlen > 0) {
38754#if defined(DUK_USE_HEAPPTR16)
38755 lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
38756#else
38757 lst = e->u.strlist;
38758#endif
38759 DUK_ASSERT(lst != NULL);
38760
38761 for (j = 0; j < e->listlen; j++) {
38762#if defined(DUK_USE_HEAPPTR16)
38763 h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[j]);
38764#else
38765 h = lst[j];
38766#endif
38767 if (h != NULL) {
38768 duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h);
38769 }
38770 }
38771 } else {
38772#if defined(DUK_USE_HEAPPTR16)
38773 h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16);
38774#else
38775 h = e->u.str;
38776#endif
38777 if (h != NULL) {
38778 duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h);
38779 }
38780 }
38781 }
38782}
38783#endif /* DUK_USE_STRTAB_CHAIN */
38784
38785#if defined(DUK_USE_STRTAB_PROBE)
38786DUK_LOCAL void duk__debug_dump_strtab_probe(duk_hthread *thr, duk_heap *heap) {
38787 duk_uint32_t i;
38788 duk_hstring *h;
38789
38790 for (i = 0; i < heap->st_size; i++) {
38791#if defined(DUK_USE_HEAPPTR16)
11fdf7f2 38792 h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]);
7c673cae
FG
38793#else
38794 h = heap->strtable[i];
38795#endif
38796 if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) {
38797 continue;
38798 }
38799
38800 duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h);
38801 }
38802}
38803#endif /* DUK_USE_STRTAB_PROBE */
38804
38805DUK_LOCAL void duk__debug_handle_dump_heap(duk_hthread *thr, duk_heap *heap) {
11fdf7f2 38806 DUK_D(DUK_DPRINT("debug command DumpHeap"));
7c673cae
FG
38807
38808 duk_debug_write_reply(thr);
38809 duk__debug_dump_heap_allocated(thr, heap);
38810#if defined(DUK_USE_STRTAB_CHAIN)
38811 duk__debug_dump_strtab_chain(thr, heap);
38812#endif
38813#if defined(DUK_USE_STRTAB_PROBE)
38814 duk__debug_dump_strtab_probe(thr, heap);
38815#endif
38816 duk_debug_write_eom(thr);
38817}
38818#endif /* DUK_USE_DEBUGGER_DUMPHEAP */
38819
38820DUK_LOCAL void duk__debug_handle_get_bytecode(duk_hthread *thr, duk_heap *heap) {
38821 duk_activation *act;
11fdf7f2 38822 duk_hcompiledfunction *fun = NULL;
7c673cae
FG
38823 duk_size_t i, n;
38824 duk_tval *tv;
38825 duk_hobject **fn;
11fdf7f2
TL
38826 duk_int32_t level = -1;
38827 duk_uint8_t ibyte;
7c673cae
FG
38828
38829 DUK_UNREF(heap);
38830
11fdf7f2 38831 DUK_D(DUK_DPRINT("debug command GetBytecode"));
7c673cae 38832
11fdf7f2
TL
38833 ibyte = duk_debug_peek_byte(thr);
38834 if (ibyte != DUK_DBG_IB_EOM) {
38835 tv = duk_debug_read_tval(thr);
38836 if (tv == NULL) {
38837 /* detached */
38838 return;
38839 }
38840 if (DUK_TVAL_IS_OBJECT(tv)) {
38841 /* tentative, checked later */
38842 fun = (duk_hcompiledfunction *) DUK_TVAL_GET_OBJECT(tv);
38843 DUK_ASSERT(fun != NULL);
38844 } else if (DUK_TVAL_IS_NUMBER(tv)) {
38845 level = (duk_int32_t) DUK_TVAL_GET_NUMBER(tv);
38846 } else {
38847 DUK_D(DUK_DPRINT("invalid argument to GetBytecode: %!T", tv));
38848 goto fail_args;
38849 }
38850 }
38851
38852 if (fun == NULL) {
38853 if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
38854 DUK_D(DUK_DPRINT("invalid callstack level for GetBytecode"));
38855 goto fail_level;
38856 }
38857 act = thr->callstack + thr->callstack_top + level;
7c673cae 38858 fun = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
11fdf7f2
TL
38859 }
38860
38861 if (fun == NULL || !DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) fun)) {
38862 DUK_D(DUK_DPRINT("invalid argument to GetBytecode: %!O", fun));
38863 goto fail_args;
38864 }
38865 DUK_ASSERT(fun != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) fun));
38866
38867 duk_debug_write_reply(thr);
38868 n = DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(heap, fun);
38869 duk_debug_write_int(thr, (duk_int32_t) n);
38870 tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(heap, fun);
38871 for (i = 0; i < n; i++) {
38872 duk_debug_write_tval(thr, tv);
38873 tv++;
38874 }
38875 n = DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(heap, fun);
38876 duk_debug_write_int(thr, (duk_int32_t) n);
38877 fn = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(heap, fun);
38878 for (i = 0; i < n; i++) {
38879 duk_debug_write_hobject(thr, *fn);
38880 fn++;
38881 }
38882 duk_debug_write_string(thr,
38883 (const char *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(heap, fun),
38884 (duk_size_t) DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE(heap, fun));
38885 duk_debug_write_eom(thr);
38886 return;
38887
38888 fail_args:
38889 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid argument");
38890 return;
38891
38892 fail_level:
38893 duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack level");
38894 return;
38895}
38896
38897/*
38898 * Object inspection commands: GetHeapObjInfo, GetObjPropDesc,
38899 * GetObjPropDescRange
38900 */
38901
38902#if defined(DUK_USE_DEBUGGER_INSPECT)
38903
38904#if 0 /* pruned */
38905DUK_LOCAL const char * const duk__debug_getinfo_heaphdr_keys[] = {
38906 "reachable",
38907 "temproot",
38908 "finalizable",
38909 "finalized",
38910 "readonly"
38911 /* NULL not needed here */
38912};
38913DUK_LOCAL duk_uint_t duk__debug_getinfo_heaphdr_masks[] = {
38914 DUK_HEAPHDR_FLAG_REACHABLE,
38915 DUK_HEAPHDR_FLAG_TEMPROOT,
38916 DUK_HEAPHDR_FLAG_FINALIZABLE,
38917 DUK_HEAPHDR_FLAG_FINALIZED,
38918 DUK_HEAPHDR_FLAG_READONLY,
38919 0 /* terminator */
38920};
38921#endif
38922DUK_LOCAL const char * const duk__debug_getinfo_hstring_keys[] = {
38923#if 0
38924 "arridx",
38925 "internal",
38926 "reserved_word",
38927 "strict_reserved_word",
38928 "eval_or_arguments",
38929#endif
38930 "extdata"
38931 /* NULL not needed here */
38932};
38933DUK_LOCAL duk_uint_t duk__debug_getinfo_hstring_masks[] = {
38934#if 0
38935 DUK_HSTRING_FLAG_ARRIDX,
38936 DUK_HSTRING_FLAG_INTERNAL,
38937 DUK_HSTRING_FLAG_RESERVED_WORD,
38938 DUK_HSTRING_FLAG_STRICT_RESERVED_WORD,
38939 DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS,
38940#endif
38941 DUK_HSTRING_FLAG_EXTDATA,
38942 0 /* terminator */
38943};
38944DUK_LOCAL const char * const duk__debug_getinfo_hobject_keys[] = {
38945 "extensible",
38946 "constructable",
38947 "bound",
38948 "compiledfunction",
38949 "nativefunction",
38950 "bufferobject",
38951 "thread",
38952 "array_part",
38953 "strict",
38954 "notail",
38955 "newenv",
38956 "namebinding",
38957 "createargs",
38958 "envrecclosed",
38959 "exotic_array",
38960 "exotic_stringobj",
38961 "exotic_arguments",
38962 "exotic_dukfunc",
38963 "exotic_proxyobj"
38964 /* NULL not needed here */
38965};
38966DUK_LOCAL duk_uint_t duk__debug_getinfo_hobject_masks[] = {
38967 DUK_HOBJECT_FLAG_EXTENSIBLE,
38968 DUK_HOBJECT_FLAG_CONSTRUCTABLE,
38969 DUK_HOBJECT_FLAG_BOUND,
38970 DUK_HOBJECT_FLAG_COMPILEDFUNCTION,
38971 DUK_HOBJECT_FLAG_NATIVEFUNCTION,
38972 DUK_HOBJECT_FLAG_BUFFEROBJECT,
38973 DUK_HOBJECT_FLAG_THREAD,
38974 DUK_HOBJECT_FLAG_ARRAY_PART,
38975 DUK_HOBJECT_FLAG_STRICT,
38976 DUK_HOBJECT_FLAG_NOTAIL,
38977 DUK_HOBJECT_FLAG_NEWENV,
38978 DUK_HOBJECT_FLAG_NAMEBINDING,
38979 DUK_HOBJECT_FLAG_CREATEARGS,
38980 DUK_HOBJECT_FLAG_ENVRECCLOSED,
38981 DUK_HOBJECT_FLAG_EXOTIC_ARRAY,
38982 DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ,
38983 DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS,
38984 DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC,
38985 DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ,
38986 0 /* terminator */
38987};
38988DUK_LOCAL const char * const duk__debug_getinfo_hbuffer_keys[] = {
38989 "dynamic",
38990 "external"
38991 /* NULL not needed here */
38992};
38993DUK_LOCAL duk_uint_t duk__debug_getinfo_hbuffer_masks[] = {
38994 DUK_HBUFFER_FLAG_DYNAMIC,
38995 DUK_HBUFFER_FLAG_EXTERNAL,
38996 0 /* terminator */
38997};
38998
38999DUK_LOCAL void duk__debug_getinfo_flags_key(duk_hthread *thr, const char *key) {
39000 duk_debug_write_uint(thr, 0);
39001 duk_debug_write_cstring(thr, key);
39002}
39003
39004DUK_LOCAL void duk__debug_getinfo_prop_uint(duk_hthread *thr, const char *key, duk_uint_t val) {
39005 duk_debug_write_uint(thr, 0);
39006 duk_debug_write_cstring(thr, key);
39007 duk_debug_write_uint(thr, val);
39008}
39009
39010DUK_LOCAL void duk__debug_getinfo_prop_int(duk_hthread *thr, const char *key, duk_int_t val) {
39011 duk_debug_write_uint(thr, 0);
39012 duk_debug_write_cstring(thr, key);
39013 duk_debug_write_int(thr, val);
39014}
39015
39016DUK_LOCAL void duk__debug_getinfo_prop_bool(duk_hthread *thr, const char *key, duk_bool_t val) {
39017 duk_debug_write_uint(thr, 0);
39018 duk_debug_write_cstring(thr, key);
39019 duk_debug_write_boolean(thr, val);
39020}
39021
39022DUK_LOCAL void duk__debug_getinfo_bitmask(duk_hthread *thr, const char * const * keys, duk_uint_t *masks, duk_uint_t flags) {
39023 const char *key;
39024 duk_uint_t mask;
39025
39026 for (;;) {
39027 mask = *masks++;
39028 if (!mask) {
39029 break;
7c673cae 39030 }
11fdf7f2
TL
39031 key = *keys++;
39032 DUK_ASSERT(key != NULL);
39033
39034 DUK_DD(DUK_DDPRINT("inspect bitmask: key=%s, mask=0x%08lx, flags=0x%08lx", key, (unsigned long) mask, (unsigned long) flags));
39035 duk__debug_getinfo_prop_bool(thr, key, flags & mask);
7c673cae 39036 }
11fdf7f2 39037}
7c673cae 39038
11fdf7f2
TL
39039/* Inspect a property using a virtual index into a conceptual property list
39040 * consisting of (1) all array part items from [0,a_size[ (even when above
39041 * .length) and (2) all entry part items from [0,e_next[. Unused slots are
39042 * indicated using dvalue 'unused'.
39043 */
39044DUK_LOCAL duk_bool_t duk__debug_getprop_index(duk_hthread *thr, duk_heap *heap, duk_hobject *h_obj, duk_uint_t idx) {
39045 duk_uint_t a_size;
39046 duk_tval *tv;
39047 duk_hstring *h_key;
39048 duk_hobject *h_getset;
39049 duk_uint_t flags;
39050
39051 DUK_UNREF(heap);
39052
39053 a_size = DUK_HOBJECT_GET_ASIZE(h_obj);
39054 if (idx < a_size) {
39055 duk_debug_write_uint(thr, DUK_PROPDESC_FLAGS_WEC);
39056 duk_debug_write_uint(thr, idx);
39057 tv = DUK_HOBJECT_A_GET_VALUE_PTR(heap, h_obj, idx);
39058 duk_debug_write_tval(thr, tv);
39059 return 1;
39060 }
39061
39062 idx -= a_size;
39063 if (idx >= DUK_HOBJECT_GET_ENEXT(h_obj)) {
39064 return 0;
39065 }
39066
39067 h_key = DUK_HOBJECT_E_GET_KEY(heap, h_obj, idx);
39068 if (h_key == NULL) {
39069 duk_debug_write_uint(thr, 0);
39070 duk_debug_write_null(thr);
39071 duk_debug_write_unused(thr);
39072 return 1;
39073 }
39074
39075 flags = DUK_HOBJECT_E_GET_FLAGS(heap, h_obj, idx);
39076 if (DUK_HSTRING_HAS_INTERNAL(h_key)) {
39077 flags |= DUK_DBG_PROPFLAG_INTERNAL;
39078 }
39079 duk_debug_write_uint(thr, flags);
39080 duk_debug_write_hstring(thr, h_key);
39081 if (flags & DUK_PROPDESC_FLAG_ACCESSOR) {
39082 h_getset = DUK_HOBJECT_E_GET_VALUE_GETTER(heap, h_obj, idx);
39083 if (h_getset) {
39084 duk_debug_write_hobject(thr, h_getset);
39085 } else {
39086 duk_debug_write_null(thr);
7c673cae 39087 }
11fdf7f2
TL
39088 h_getset = DUK_HOBJECT_E_GET_VALUE_SETTER(heap, h_obj, idx);
39089 if (h_getset) {
39090 duk_debug_write_hobject(thr, h_getset);
39091 } else {
39092 duk_debug_write_null(thr);
39093 }
39094 } else {
39095 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, h_obj, idx);
39096 duk_debug_write_tval(thr, tv);
39097 }
39098 return 1;
39099}
7c673cae 39100
11fdf7f2
TL
39101DUK_LOCAL void duk__debug_handle_get_heap_obj_info(duk_hthread *thr, duk_heap *heap) {
39102 duk_heaphdr *h;
39103
39104 DUK_D(DUK_DPRINT("debug command GetHeapObjInfo"));
39105 DUK_UNREF(heap);
39106
39107 h = duk_debug_read_any_ptr(thr);
39108 if (!h) {
39109 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid target");
39110 return;
39111 }
39112
39113 duk_debug_write_reply(thr);
39114
39115 /* As with all inspection code, we rely on the debug client providing
39116 * a valid, non-stale pointer: there's no portable way to safely
39117 * validate the pointer here.
39118 */
39119
39120 duk__debug_getinfo_flags_key(thr, "heapptr");
39121 duk_debug_write_heapptr(thr, h);
39122
39123 /* XXX: comes out as signed now */
39124 duk__debug_getinfo_prop_uint(thr, "heaphdr_flags", (duk_uint_t) DUK_HEAPHDR_GET_FLAGS(h));
39125 duk__debug_getinfo_prop_uint(thr, "heaphdr_type", (duk_uint_t) DUK_HEAPHDR_GET_TYPE(h));
39126#if defined(DUK_USE_REFERENCE_COUNTING)
39127 duk__debug_getinfo_prop_uint(thr, "refcount", (duk_uint_t) DUK_HEAPHDR_GET_REFCOUNT(h));
39128#endif
39129#if 0 /* pruned */
39130 duk__debug_getinfo_bitmask(thr,
39131 duk__debug_getinfo_heaphdr_keys,
39132 duk__debug_getinfo_heaphdr_masks,
39133 DUK_HEAPHDR_GET_FLAGS_RAW(h));
39134#endif
39135
39136 switch (DUK_HEAPHDR_GET_TYPE(h)) {
39137 case DUK_HTYPE_STRING: {
39138 duk_hstring *h_str;
39139
39140 h_str = (duk_hstring *) h;
39141 duk__debug_getinfo_bitmask(thr,
39142 duk__debug_getinfo_hstring_keys,
39143 duk__debug_getinfo_hstring_masks,
39144 DUK_HEAPHDR_GET_FLAGS_RAW(h));
39145 duk__debug_getinfo_prop_uint(thr, "bytelen", DUK_HSTRING_GET_BYTELEN(h_str));
39146 duk__debug_getinfo_prop_uint(thr, "charlen", DUK_HSTRING_GET_CHARLEN(h_str));
39147 duk__debug_getinfo_prop_uint(thr, "hash", DUK_HSTRING_GET_HASH(h_str));
39148 duk__debug_getinfo_flags_key(thr, "data");
39149 duk_debug_write_hstring(thr, h_str);
39150 break;
39151 }
39152 case DUK_HTYPE_OBJECT: {
39153 duk_hobject *h_obj;
39154 duk_hobject *h_proto;
39155
39156 h_obj = (duk_hobject *) h;
39157 h_proto = DUK_HOBJECT_GET_PROTOTYPE(heap, h_obj);
39158
39159 /* duk_hobject specific fields. */
39160 duk__debug_getinfo_bitmask(thr,
39161 duk__debug_getinfo_hobject_keys,
39162 duk__debug_getinfo_hobject_masks,
39163 DUK_HEAPHDR_GET_FLAGS_RAW(h));
39164 duk__debug_getinfo_prop_uint(thr, "class_number", DUK_HOBJECT_GET_CLASS_NUMBER(h_obj));
39165 duk__debug_getinfo_flags_key(thr, "class_name");
39166 duk_debug_write_hstring(thr, DUK_HOBJECT_GET_CLASS_STRING(heap, h_obj));
39167 duk__debug_getinfo_flags_key(thr, "prototype");
39168 if (h_proto != NULL) {
39169 duk_debug_write_hobject(thr, h_proto);
39170 } else {
39171 duk_debug_write_null(thr);
39172 }
39173 duk__debug_getinfo_flags_key(thr, "props");
39174 duk_debug_write_pointer(thr, (void *) DUK_HOBJECT_GET_PROPS(heap, h_obj));
39175 duk__debug_getinfo_prop_uint(thr, "e_size", (duk_uint_t) DUK_HOBJECT_GET_ESIZE(h_obj));
39176 duk__debug_getinfo_prop_uint(thr, "e_next", (duk_uint_t) DUK_HOBJECT_GET_ENEXT(h_obj));
39177 duk__debug_getinfo_prop_uint(thr, "a_size", (duk_uint_t) DUK_HOBJECT_GET_ASIZE(h_obj));
39178 duk__debug_getinfo_prop_uint(thr, "h_size", (duk_uint_t) DUK_HOBJECT_GET_HSIZE(h_obj));
39179
39180 /* duk_hnativefunction specific fields. */
39181 if (DUK_HOBJECT_IS_NATIVEFUNCTION(h_obj)) {
39182 duk_hnativefunction *h_fun;
39183 h_fun = (duk_hnativefunction *) h_obj;
39184
39185 duk__debug_getinfo_prop_int(thr, "nargs", h_fun->nargs);
39186 duk__debug_getinfo_prop_int(thr, "magic", h_fun->magic);
39187 duk__debug_getinfo_prop_bool(thr, "varargs", h_fun->magic == DUK_HNATIVEFUNCTION_NARGS_VARARGS);
39188 /* Native function pointer may be different from a void pointer,
39189 * and we serialize it from memory directly now (no byte swapping etc).
39190 */
39191 duk__debug_getinfo_flags_key(thr, "funcptr");
39192 duk_debug_write_buffer(thr, (const char *) &h_fun->func, sizeof(h_fun->func));
7c673cae
FG
39193 }
39194
11fdf7f2
TL
39195 if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h_obj)) {
39196 duk_hcompiledfunction *h_fun;
39197 duk_hbuffer *h_buf;
39198 h_fun = (duk_hcompiledfunction *) h_obj;
39199
39200 duk__debug_getinfo_prop_int(thr, "nregs", h_fun->nregs);
39201 duk__debug_getinfo_prop_int(thr, "nargs", h_fun->nargs);
39202 duk__debug_getinfo_prop_uint(thr, "start_line", h_fun->start_line);
39203 duk__debug_getinfo_prop_uint(thr, "end_line", h_fun->end_line);
39204 h_buf = (duk_hbuffer *) DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, h_fun);
39205 if (h_buf != NULL) {
39206 duk__debug_getinfo_flags_key(thr, "data");
39207 duk_debug_write_heapptr(thr, (duk_heaphdr *) h_buf);
39208 }
39209 }
39210
39211 if (DUK_HOBJECT_IS_THREAD(h_obj)) {
39212 /* XXX: Currently no inspection of threads, e.g. value stack, call
39213 * stack, catch stack, etc.
39214 */
39215 duk_hthread *h_thr;
39216 h_thr = (duk_hthread *) h_obj;
39217 DUK_UNREF(h_thr);
39218 }
39219
39220 if (DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) {
39221 duk_hbufferobject *h_bufobj;
39222 h_bufobj = (duk_hbufferobject *) h_obj;
39223
39224 duk__debug_getinfo_prop_uint(thr, "slice_offset", h_bufobj->offset);
39225 duk__debug_getinfo_prop_uint(thr, "slice_length", h_bufobj->length);
39226 duk__debug_getinfo_prop_uint(thr, "elem_shift", (duk_uint_t) h_bufobj->shift);
39227 duk__debug_getinfo_prop_uint(thr, "elem_type", (duk_uint_t) h_bufobj->elem_type);
39228 duk__debug_getinfo_prop_bool(thr, "is_view", (duk_uint_t) h_bufobj->is_view);
39229 if (h_bufobj->buf != NULL) {
39230 duk__debug_getinfo_flags_key(thr, "buffer");
39231 duk_debug_write_heapptr(thr, (duk_heaphdr *) h_bufobj->buf);
39232 }
39233 }
39234 break;
39235 }
39236 case DUK_HTYPE_BUFFER: {
39237 duk_hbuffer *h_buf;
39238
39239 h_buf = (duk_hbuffer *) h;
39240 duk__debug_getinfo_bitmask(thr,
39241 duk__debug_getinfo_hbuffer_keys,
39242 duk__debug_getinfo_hbuffer_masks,
39243 DUK_HEAPHDR_GET_FLAGS_RAW(h));
39244 duk__debug_getinfo_prop_uint(thr, "size", (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_buf));
39245 duk__debug_getinfo_flags_key(thr, "dataptr");
39246 duk_debug_write_pointer(thr, (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_buf));
39247 duk__debug_getinfo_flags_key(thr, "data");
39248 duk_debug_write_hbuffer(thr, h_buf); /* tolerates NULL h_buf */
39249 break;
39250 }
39251 default: {
39252 /* Since we already started writing the reply, just emit nothing. */
39253 DUK_D(DUK_DPRINT("inspect target pointer has invalid heaphdr type"));
39254 }
39255 }
39256
39257 duk_debug_write_eom(thr);
39258}
39259
39260DUK_LOCAL void duk__debug_handle_get_obj_prop_desc(duk_hthread *thr, duk_heap *heap) {
39261 duk_heaphdr *h;
39262 duk_hobject *h_obj;
39263 duk_hstring *h_key;
39264 duk_propdesc desc;
39265
39266 DUK_D(DUK_DPRINT("debug command GetObjPropDesc"));
39267 DUK_UNREF(heap);
39268
39269 h = duk_debug_read_any_ptr(thr);
39270 if (!h) {
39271 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid target");
39272 return;
39273 }
39274 h_key = duk_debug_read_hstring(thr);
39275 if (h == NULL || DUK_HEAPHDR_GET_TYPE(h) != DUK_HTYPE_OBJECT || h_key == NULL) {
39276 goto fail_args;
39277 }
39278 h_obj = (duk_hobject *) h;
39279
39280 if (duk_hobject_get_own_propdesc(thr, h_obj, h_key, &desc, 0 /*flags*/)) {
39281 duk_int_t virtual_idx;
39282 duk_bool_t rc;
39283
39284 /* To use the shared helper need the virtual index. */
39285 DUK_ASSERT(desc.e_idx >= 0 || desc.a_idx >= 0);
39286 virtual_idx = (desc.a_idx >= 0 ? desc.a_idx :
39287 (duk_int_t) DUK_HOBJECT_GET_ASIZE(h_obj) + desc.e_idx);
39288
39289 duk_debug_write_reply(thr);
39290 rc = duk__debug_getprop_index(thr, heap, h_obj, (duk_uint_t) virtual_idx);
39291 DUK_ASSERT(rc == 1);
39292 DUK_UNREF(rc);
39293 duk_debug_write_eom(thr);
7c673cae 39294 } else {
11fdf7f2
TL
39295 duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "not found");
39296 }
39297 return;
39298
39299 fail_args:
39300 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid args");
39301}
39302
39303DUK_LOCAL void duk__debug_handle_get_obj_prop_desc_range(duk_hthread *thr, duk_heap *heap) {
39304 duk_heaphdr *h;
39305 duk_hobject *h_obj;
39306 duk_uint_t idx, idx_start, idx_end;
39307
39308 DUK_D(DUK_DPRINT("debug command GetObjPropDescRange"));
39309 DUK_UNREF(heap);
39310
39311 h = duk_debug_read_any_ptr(thr);
39312 idx_start = duk_debug_read_int(thr);
39313 idx_end = duk_debug_read_int(thr);
39314 if (h == NULL || DUK_HEAPHDR_GET_TYPE(h) != DUK_HTYPE_OBJECT) {
39315 goto fail_args;
39316 }
39317 h_obj = (duk_hobject *) h;
39318
39319 /* The index range space is conceptually the array part followed by the
39320 * entry part. Unlike normal enumeration all slots are exposed here as
39321 * is and return 'unused' if the slots are not in active use. In particular
39322 * the array part is included for the full a_size regardless of what the
39323 * array .length is.
39324 */
39325
39326 duk_debug_write_reply(thr);
39327 for (idx = idx_start; idx < idx_end; idx++) {
39328 if (!duk__debug_getprop_index(thr, heap, h_obj, idx)) {
39329 break;
39330 }
7c673cae
FG
39331 }
39332 duk_debug_write_eom(thr);
11fdf7f2
TL
39333 return;
39334
39335 fail_args:
39336 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid args");
7c673cae
FG
39337}
39338
11fdf7f2
TL
39339#endif /* DUK_USE_DEBUGGER_INSPECT */
39340
39341/*
39342 * Process incoming debug requests
39343 *
39344 * Individual request handlers can push temporaries on the value stack and
39345 * rely on duk__debug_process_message() to restore the value stack top
39346 * automatically.
39347 */
39348
39349/* Process one debug message. Automatically restore value stack top to its
39350 * entry value, so that individual message handlers don't need exact value
39351 * stack handling which is convenient.
39352 */
7c673cae
FG
39353DUK_LOCAL void duk__debug_process_message(duk_hthread *thr) {
39354 duk_context *ctx = (duk_context *) thr;
39355 duk_heap *heap;
39356 duk_uint8_t x;
39357 duk_int32_t cmd;
11fdf7f2 39358 duk_idx_t entry_top;
7c673cae
FG
39359
39360 DUK_ASSERT(thr != NULL);
39361 heap = thr->heap;
39362 DUK_ASSERT(heap != NULL);
39363 DUK_UNREF(ctx);
39364
11fdf7f2
TL
39365 entry_top = duk_get_top(ctx);
39366
7c673cae
FG
39367 x = duk_debug_read_byte(thr);
39368 switch (x) {
11fdf7f2 39369 case DUK_DBG_IB_REQUEST: {
7c673cae
FG
39370 cmd = duk_debug_read_int(thr);
39371 switch (cmd) {
39372 case DUK_DBG_CMD_BASICINFO: {
39373 duk__debug_handle_basic_info(thr, heap);
39374 break;
39375 }
39376 case DUK_DBG_CMD_TRIGGERSTATUS: {
39377 duk__debug_handle_trigger_status(thr, heap);
39378 break;
39379 }
39380 case DUK_DBG_CMD_PAUSE: {
39381 duk__debug_handle_pause(thr, heap);
39382 break;
39383 }
39384 case DUK_DBG_CMD_RESUME: {
39385 duk__debug_handle_resume(thr, heap);
39386 break;
39387 }
39388 case DUK_DBG_CMD_STEPINTO:
39389 case DUK_DBG_CMD_STEPOVER:
39390 case DUK_DBG_CMD_STEPOUT: {
39391 duk__debug_handle_step(thr, heap, cmd);
39392 break;
39393 }
39394 case DUK_DBG_CMD_LISTBREAK: {
39395 duk__debug_handle_list_break(thr, heap);
39396 break;
39397 }
39398 case DUK_DBG_CMD_ADDBREAK: {
39399 duk__debug_handle_add_break(thr, heap);
39400 break;
39401 }
39402 case DUK_DBG_CMD_DELBREAK: {
39403 duk__debug_handle_del_break(thr, heap);
39404 break;
39405 }
39406 case DUK_DBG_CMD_GETVAR: {
39407 duk__debug_handle_get_var(thr, heap);
39408 break;
39409 }
39410 case DUK_DBG_CMD_PUTVAR: {
39411 duk__debug_handle_put_var(thr, heap);
39412 break;
39413 }
39414 case DUK_DBG_CMD_GETCALLSTACK: {
39415 duk__debug_handle_get_call_stack(thr, heap);
39416 break;
39417 }
39418 case DUK_DBG_CMD_GETLOCALS: {
39419 duk__debug_handle_get_locals(thr, heap);
39420 break;
39421 }
39422 case DUK_DBG_CMD_EVAL: {
39423 duk__debug_handle_eval(thr, heap);
39424 break;
39425 }
39426 case DUK_DBG_CMD_DETACH: {
11fdf7f2
TL
39427 /* The actual detached_cb call is postponed to message loop so
39428 * we don't need any special precautions here (just skip to EOM
39429 * on the already closed connection).
39430 */
7c673cae
FG
39431 duk__debug_handle_detach(thr, heap);
39432 break;
39433 }
39434#if defined(DUK_USE_DEBUGGER_DUMPHEAP)
39435 case DUK_DBG_CMD_DUMPHEAP: {
39436 duk__debug_handle_dump_heap(thr, heap);
39437 break;
39438 }
39439#endif /* DUK_USE_DEBUGGER_DUMPHEAP */
39440 case DUK_DBG_CMD_GETBYTECODE: {
39441 duk__debug_handle_get_bytecode(thr, heap);
39442 break;
39443 }
11fdf7f2
TL
39444 case DUK_DBG_CMD_APPREQUEST: {
39445 duk__debug_handle_apprequest(thr, heap);
39446 break;
39447 }
39448#if defined(DUK_USE_DEBUGGER_INSPECT)
39449 case DUK_DBG_CMD_GETHEAPOBJINFO: {
39450 duk__debug_handle_get_heap_obj_info(thr, heap);
39451 break;
39452 }
39453 case DUK_DBG_CMD_GETOBJPROPDESC: {
39454 duk__debug_handle_get_obj_prop_desc(thr, heap);
39455 break;
39456 }
39457 case DUK_DBG_CMD_GETOBJPROPDESCRANGE: {
39458 duk__debug_handle_get_obj_prop_desc_range(thr, heap);
39459 break;
39460 }
39461#endif /* DUK_USE_DEBUGGER_INSPECT */
7c673cae
FG
39462 default: {
39463 DUK_D(DUK_DPRINT("debug command unsupported: %d", (int) cmd));
39464 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNSUPPORTED, "unsupported command");
39465 }
39466 } /* switch cmd */
39467 break;
39468 }
11fdf7f2 39469 case DUK_DBG_IB_REPLY: {
7c673cae
FG
39470 DUK_D(DUK_DPRINT("debug reply, skipping"));
39471 break;
39472 }
11fdf7f2 39473 case DUK_DBG_IB_ERROR: {
7c673cae
FG
39474 DUK_D(DUK_DPRINT("debug error, skipping"));
39475 break;
39476 }
11fdf7f2 39477 case DUK_DBG_IB_NOTIFY: {
7c673cae
FG
39478 DUK_D(DUK_DPRINT("debug notify, skipping"));
39479 break;
39480 }
39481 default: {
39482 DUK_D(DUK_DPRINT("invalid initial byte, drop connection: %d", (int) x));
39483 goto fail;
39484 }
39485 } /* switch initial byte */
39486
11fdf7f2
TL
39487 DUK_ASSERT(duk_get_top(ctx) >= entry_top);
39488 duk_set_top(ctx, entry_top);
7c673cae
FG
39489 duk__debug_skip_to_eom(thr);
39490 return;
39491
39492 fail:
11fdf7f2
TL
39493 DUK_ASSERT(duk_get_top(ctx) >= entry_top);
39494 duk_set_top(ctx, entry_top);
39495 DUK__SET_CONN_BROKEN(thr, 1);
7c673cae
FG
39496 return;
39497}
39498
11fdf7f2
TL
39499DUK_LOCAL void duk__check_resend_status(duk_hthread *thr) {
39500 if (thr->heap->dbg_read_cb != NULL && thr->heap->dbg_state_dirty) {
39501 duk_debug_send_status(thr);
39502 thr->heap->dbg_state_dirty = 0;
39503 }
39504}
39505
7c673cae
FG
39506DUK_INTERNAL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t no_block) {
39507 duk_context *ctx = (duk_context *) thr;
39508#if defined(DUK_USE_ASSERTIONS)
39509 duk_idx_t entry_top;
39510#endif
39511 duk_bool_t retval = 0;
39512
39513 DUK_ASSERT(thr != NULL);
39514 DUK_UNREF(ctx);
11fdf7f2 39515 DUK_ASSERT(thr->heap != NULL);
7c673cae
FG
39516#if defined(DUK_USE_ASSERTIONS)
39517 entry_top = duk_get_top(ctx);
39518#endif
39519
11fdf7f2
TL
39520 DUK_D(DUK_DPRINT("process debug messages: read_cb=%s, no_block=%ld, detaching=%ld, processing=%ld",
39521 thr->heap->dbg_read_cb ? "not NULL" : "NULL", (long) no_block,
39522 (long) thr->heap->dbg_detaching, (long) thr->heap->dbg_processing));
7c673cae
FG
39523 DUK_DD(DUK_DDPRINT("top at entry: %ld", (long) duk_get_top(ctx)));
39524
11fdf7f2
TL
39525 /* thr->heap->dbg_detaching may be != 0 if a debugger write outside
39526 * the message loop caused a transport error and detach1() to run.
39527 */
39528 DUK_ASSERT(thr->heap->dbg_detaching == 0 || thr->heap->dbg_detaching == 1);
39529 DUK_ASSERT(thr->heap->dbg_processing == 0);
39530 thr->heap->dbg_processing = 1;
39531
39532 /* Ensure dirty state causes a Status even if never process any
39533 * messages. This is expected by the bytecode executor when in
39534 * the running state.
39535 */
39536 duk__check_resend_status(thr);
39537
7c673cae
FG
39538 for (;;) {
39539 /* Process messages until we're no longer paused or we peek
39540 * and see there's nothing to read right now.
39541 */
39542 DUK_DD(DUK_DDPRINT("top at loop top: %ld", (long) duk_get_top(ctx)));
11fdf7f2
TL
39543 DUK_ASSERT(thr->heap->dbg_processing == 1);
39544
39545 while (thr->heap->dbg_read_cb == NULL && thr->heap->dbg_detaching) {
39546 /* Detach is pending; can be triggered from outside the
39547 * debugger loop (e.g. Status notify write error) or by
39548 * previous message handling. Call detached callback
39549 * here, in a controlled state, to ensure a possible
39550 * reattach inside the detached_cb is handled correctly.
39551 *
39552 * Recheck for detach in a while loop: an immediate
39553 * reattach involves a call to duk_debugger_attach()
39554 * which writes a debugger handshake line immediately
39555 * inside the API call. If the transport write fails
39556 * for that handshake, we can immediately end up in a
39557 * "transport broken, detaching" case several times here.
39558 * Loop back until we're either cleanly attached or
39559 * fully detached.
39560 *
39561 * NOTE: Reset dbg_processing = 1 forcibly, in case we
39562 * re-attached; duk_debugger_attach() sets dbg_processing
39563 * to 0 at the moment.
39564 */
39565
39566 DUK_D(DUK_DPRINT("detach pending (dbg_read_cb == NULL, dbg_detaching != 0), call detach2"));
39567
39568 duk__debug_do_detach2(thr->heap);
39569 thr->heap->dbg_processing = 1; /* may be set to 0 by duk_debugger_attach() inside callback */
39570
39571 DUK_D(DUK_DPRINT("after detach2 (and possible reattach): dbg_read_cb=%s, dbg_detaching=%ld",
39572 thr->heap->dbg_read_cb ? "not NULL" : "NULL", (long) thr->heap->dbg_detaching));
39573 }
39574 DUK_ASSERT(thr->heap->dbg_detaching == 0); /* true even with reattach */
39575 DUK_ASSERT(thr->heap->dbg_processing == 1); /* even after a detach and possible reattach */
7c673cae
FG
39576
39577 if (thr->heap->dbg_read_cb == NULL) {
11fdf7f2 39578 DUK_D(DUK_DPRINT("debug connection broken (and not detaching), stop processing messages"));
7c673cae 39579 break;
11fdf7f2
TL
39580 }
39581
39582 if (!thr->heap->dbg_paused || no_block) {
7c673cae 39583 if (!duk_debug_read_peek(thr)) {
11fdf7f2
TL
39584 /* Note: peek cannot currently trigger a detach
39585 * so the dbg_detaching == 0 assert outside the
39586 * loop is correct.
39587 */
39588 DUK_D(DUK_DPRINT("processing debug message, peek indicated no data, stop processing messages"));
7c673cae
FG
39589 break;
39590 }
39591 DUK_D(DUK_DPRINT("processing debug message, peek indicated there is data, handle it"));
39592 } else {
39593 DUK_D(DUK_DPRINT("paused, process debug message, blocking if necessary"));
39594 }
39595
11fdf7f2 39596 duk__check_resend_status(thr);
7c673cae 39597 duk__debug_process_message(thr);
11fdf7f2
TL
39598 duk__check_resend_status(thr);
39599
7c673cae
FG
39600 retval = 1; /* processed one or more messages */
39601 }
39602
11fdf7f2
TL
39603 DUK_ASSERT(thr->heap->dbg_detaching == 0);
39604 DUK_ASSERT(thr->heap->dbg_processing == 1);
39605 thr->heap->dbg_processing = 0;
39606
7c673cae 39607 /* As an initial implementation, read flush after exiting the message
11fdf7f2 39608 * loop. If transport is broken, this is a no-op (with debug logs).
7c673cae 39609 */
11fdf7f2
TL
39610 duk_debug_read_flush(thr); /* this cannot initiate a detach */
39611 DUK_ASSERT(thr->heap->dbg_detaching == 0);
7c673cae
FG
39612
39613 DUK_DD(DUK_DDPRINT("top at exit: %ld", (long) duk_get_top(ctx)));
39614
39615#if defined(DUK_USE_ASSERTIONS)
39616 /* Easy to get wrong, so assert for it. */
39617 DUK_ASSERT(entry_top == duk_get_top(ctx));
39618#endif
39619
39620 return retval;
39621}
39622
11fdf7f2
TL
39623/*
39624 * Halt execution helper
39625 */
39626
39627/* Halt execution and enter a debugger message loop until execution is resumed
39628 * by the client. PC for the current activation may be temporarily decremented
39629 * so that the "current" instruction will be shown by the client. This helper
39630 * is callable from anywhere, also outside bytecode executor.
39631 */
39632
39633DUK_INTERNAL void duk_debug_halt_execution(duk_hthread *thr, duk_bool_t use_prev_pc) {
39634 duk_activation *act;
39635 duk_hcompiledfunction *fun;
39636 duk_instr_t *old_pc = NULL;
39637
39638 DUK_ASSERT(thr != NULL);
39639 DUK_ASSERT(thr->heap != NULL);
39640 DUK_ASSERT(DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap));
39641 DUK_ASSERT(thr->heap->dbg_processing == 0);
39642
39643 DUK_HEAP_SET_PAUSED(thr->heap);
39644
39645 act = duk_hthread_get_current_activation(thr);
39646
39647 /* NOTE: act may be NULL if an error is thrown outside of any activation,
39648 * which may happen in the case of, e.g. syntax errors.
39649 */
39650
39651 /* Decrement PC if that was requested, this requires a PC sync. */
39652 if (act != NULL) {
39653 duk_hthread_sync_currpc(thr);
39654 old_pc = act->curr_pc;
39655 fun = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
39656
39657 /* Short circuit if is safe: if act->curr_pc != NULL, 'fun' is
39658 * guaranteed to be a non-NULL Ecmascript function.
39659 */
39660 DUK_ASSERT(act->curr_pc == NULL ||
39661 (fun != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) fun)));
39662 if (use_prev_pc &&
39663 act->curr_pc != NULL &&
39664 act->curr_pc > DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, fun)) {
39665 act->curr_pc--;
39666 }
39667 }
39668
39669 /* Process debug messages until we are no longer paused. */
39670
39671 /* NOTE: This is a bit fragile. It's important to ensure that
39672 * duk_debug_process_messages() never throws an error or
39673 * act->curr_pc will never be reset.
39674 */
39675
39676 thr->heap->dbg_state_dirty = 1;
39677 while (thr->heap->dbg_paused) {
39678 DUK_ASSERT(DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap));
39679 DUK_ASSERT(thr->heap->dbg_processing);
39680 duk_debug_process_messages(thr, 0 /*no_block*/);
39681 }
39682
39683 /* XXX: Decrementing and restoring act->curr_pc works now, but if the
39684 * debugger message loop gains the ability to adjust the current PC
39685 * (e.g. a forced jump) restoring the PC here will break. Another
39686 * approach would be to use a state flag for the "decrement 1 from
39687 * topmost activation's PC" and take it into account whenever dealing
39688 * with PC values.
39689 */
39690 if (act != NULL) {
39691 act->curr_pc = old_pc; /* restore PC */
39692 }
39693}
39694
7c673cae
FG
39695/*
39696 * Breakpoint management
39697 */
39698
39699DUK_INTERNAL duk_small_int_t duk_debug_add_breakpoint(duk_hthread *thr, duk_hstring *filename, duk_uint32_t line) {
39700 duk_heap *heap;
39701 duk_breakpoint *b;
39702
39703 /* Caller must trigger recomputation of active breakpoint list. To
39704 * ensure stale values are not used if that doesn't happen, clear the
39705 * active breakpoint list here.
39706 */
39707
39708 DUK_ASSERT(thr != NULL);
39709 DUK_ASSERT(filename != NULL);
39710 heap = thr->heap;
39711 DUK_ASSERT(heap != NULL);
39712
39713 if (heap->dbg_breakpoint_count >= DUK_HEAP_MAX_BREAKPOINTS) {
39714 DUK_D(DUK_DPRINT("failed to add breakpoint for %O:%ld, all breakpoint slots used",
39715 (duk_heaphdr *) filename, (long) line));
39716 return -1;
39717 }
39718 heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL;
39719 b = heap->dbg_breakpoints + (heap->dbg_breakpoint_count++);
39720 b->filename = filename;
39721 b->line = line;
39722 DUK_HSTRING_INCREF(thr, filename);
39723
39724 return heap->dbg_breakpoint_count - 1; /* index */
39725}
39726
39727DUK_INTERNAL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_uint_t breakpoint_index) {
39728 duk_heap *heap;
39729 duk_hstring *h;
39730 duk_breakpoint *b;
39731 duk_size_t move_size;
39732
39733 /* Caller must trigger recomputation of active breakpoint list. To
39734 * ensure stale values are not used if that doesn't happen, clear the
39735 * active breakpoint list here.
39736 */
39737
39738 DUK_ASSERT(thr != NULL);
39739 heap = thr->heap;
39740 DUK_ASSERT(heap != NULL);
11fdf7f2 39741 DUK_ASSERT(DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap));
7c673cae
FG
39742 DUK_ASSERT_DISABLE(breakpoint_index >= 0); /* unsigned */
39743
39744 if (breakpoint_index >= heap->dbg_breakpoint_count) {
39745 DUK_D(DUK_DPRINT("invalid breakpoint index: %ld", (long) breakpoint_index));
39746 return 0;
39747 }
39748 b = heap->dbg_breakpoints + breakpoint_index;
39749
39750 h = b->filename;
39751 DUK_ASSERT(h != NULL);
39752
39753 move_size = sizeof(duk_breakpoint) * (heap->dbg_breakpoint_count - breakpoint_index - 1);
39754 if (move_size > 0) {
39755 DUK_MEMMOVE((void *) b,
11fdf7f2
TL
39756 (const void *) (b + 1),
39757 (size_t) move_size);
7c673cae
FG
39758 }
39759 heap->dbg_breakpoint_count--;
39760 heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL;
39761
39762 DUK_HSTRING_DECREF(thr, h); /* side effects */
11fdf7f2 39763 DUK_UNREF(h); /* w/o refcounting */
7c673cae
FG
39764
39765 /* Breakpoint entries above the used area are left as garbage. */
39766
39767 return 1;
39768}
39769
39770#undef DUK__SET_CONN_BROKEN
39771
39772#else /* DUK_USE_DEBUGGER_SUPPORT */
39773
39774/* No debugger support. */
39775
39776#endif /* DUK_USE_DEBUGGER_SUPPORT */
7c673cae
FG
39777/*
39778 * Augmenting errors at their creation site and their throw site.
39779 *
39780 * When errors are created, traceback data is added by built-in code
39781 * and a user error handler (if defined) can process or replace the
39782 * error. Similarly, when errors are thrown, a user error handler
39783 * (if defined) can process or replace the error.
39784 *
39785 * Augmentation and other processing at error creation time is nice
39786 * because an error is only created once, but it may be thrown and
39787 * rethrown multiple times. User error handler registered for processing
39788 * an error at its throw site must be careful to handle rethrowing in
39789 * a useful manner.
39790 *
39791 * Error augmentation may throw an internal error (e.g. alloc error).
39792 *
39793 * Ecmascript allows throwing any values, so all values cannot be
39794 * augmented. Currently, the built-in augmentation at error creation
39795 * only augments error values which are Error instances (= have the
39796 * built-in Error.prototype in their prototype chain) and are also
39797 * extensible. User error handlers have no limitations in this respect.
39798 */
39799
39800/* include removed: duk_internal.h */
39801
39802/*
39803 * Helper for calling a user error handler.
39804 *
39805 * 'thr' must be the currently active thread; the error handler is called
39806 * in its context. The valstack of 'thr' must have the error value on
39807 * top, and will be replaced by another error value based on the return
39808 * value of the error handler.
39809 *
39810 * The helper calls duk_handle_call() recursively in protected mode.
39811 * Before that call happens, no longjmps should happen; as a consequence,
39812 * we must assume that the valstack contains enough temporary space for
39813 * arguments and such.
39814 *
39815 * While the error handler runs, any errors thrown will not trigger a
39816 * recursive error handler call (this is implemented using a heap level
39817 * flag which will "follow" through any coroutines resumed inside the
39818 * error handler). If the error handler is not callable or throws an
39819 * error, the resulting error replaces the original error (for Duktape
39820 * internal errors, duk_error_throw.c further substitutes this error with
39821 * a DoubleError which is not ideal). This would be easy to change and
39822 * even signal to the caller.
39823 *
39824 * The user error handler is stored in 'Duktape.errCreate' or
39825 * 'Duktape.errThrow' depending on whether we're augmenting the error at
39826 * creation or throw time. There are several alternatives to this approach,
39827 * see doc/error-objects.rst for discussion.
39828 *
39829 * Note: since further longjmp()s may occur while calling the error handler
39830 * (for many reasons, e.g. a labeled 'break' inside the handler), the
39831 * caller can make no assumptions on the thr->heap->lj state after the
39832 * call (this affects especially duk_error_throw.c). This is not an issue
39833 * as long as the caller writes to the lj state only after the error handler
39834 * finishes.
39835 */
39836
39837#if defined(DUK_USE_ERRTHROW) || defined(DUK_USE_ERRCREATE)
39838DUK_LOCAL void duk__err_augment_user(duk_hthread *thr, duk_small_uint_t stridx_cb) {
39839 duk_context *ctx = (duk_context *) thr;
39840 duk_tval *tv_hnd;
39841 duk_small_uint_t call_flags;
39842 duk_int_t rc;
39843
39844 DUK_ASSERT(thr != NULL);
39845 DUK_ASSERT(thr->heap != NULL);
39846 DUK_ASSERT_DISABLE(stridx_cb >= 0); /* unsigned */
39847 DUK_ASSERT(stridx_cb < DUK_HEAP_NUM_STRINGS);
39848
39849 if (DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap)) {
39850 DUK_DD(DUK_DDPRINT("recursive call to error handler, ignore"));
39851 return;
39852 }
39853
39854 /*
39855 * Check whether or not we have an error handler.
39856 *
39857 * We must be careful of not triggering an error when looking up the
39858 * property. For instance, if the property is a getter, we don't want
39859 * to call it, only plain values are allowed. The value, if it exists,
39860 * is not checked. If the value is not a function, a TypeError happens
39861 * when it is called and that error replaces the original one.
39862 */
39863
39864 DUK_ASSERT_VALSTACK_SPACE(thr, 4); /* 3 entries actually needed below */
39865
39866 /* [ ... errval ] */
39867
39868 if (thr->builtins[DUK_BIDX_DUKTAPE] == NULL) {
39869 /* When creating built-ins, some of the built-ins may not be set
39870 * and we want to tolerate that when throwing errors.
39871 */
39872 DUK_DD(DUK_DDPRINT("error occurred when DUK_BIDX_DUKTAPE is NULL, ignoring"));
39873 return;
39874 }
39875 tv_hnd = duk_hobject_find_existing_entry_tval_ptr(thr->heap,
39876 thr->builtins[DUK_BIDX_DUKTAPE],
39877 DUK_HTHREAD_GET_STRING(thr, stridx_cb));
39878 if (tv_hnd == NULL) {
39879 DUK_DD(DUK_DDPRINT("error handler does not exist or is not a plain value: %!T",
39880 (duk_tval *) tv_hnd));
39881 return;
39882 }
39883 DUK_DDD(DUK_DDDPRINT("error handler dump (callability not checked): %!T",
39884 (duk_tval *) tv_hnd));
39885 duk_push_tval(ctx, tv_hnd);
39886
39887 /* [ ... errval errhandler ] */
39888
39889 duk_insert(ctx, -2); /* -> [ ... errhandler errval ] */
39890 duk_push_undefined(ctx);
39891 duk_insert(ctx, -2); /* -> [ ... errhandler undefined(= this) errval ] */
39892
39893 /* [ ... errhandler undefined errval ] */
39894
39895 /*
39896 * DUK_CALL_FLAG_IGNORE_RECLIMIT causes duk_handle_call() to ignore C
39897 * recursion depth limit (and won't increase it either). This is
39898 * dangerous, but useful because it allows the error handler to run
39899 * even if the original error is caused by C recursion depth limit.
39900 *
39901 * The heap level DUK_HEAP_FLAG_ERRHANDLER_RUNNING is set for the
39902 * duration of the error handler and cleared afterwards. This flag
39903 * prevents the error handler from running recursively. The flag is
39904 * heap level so that the flag properly controls even coroutines
39905 * launched by an error handler. Since the flag is heap level, it is
39906 * critical to restore it correctly.
39907 *
39908 * We ignore errors now: a success return and an error value both
39909 * replace the original error value. (This would be easy to change.)
39910 */
39911
39912 DUK_ASSERT(!DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap)); /* since no recursive error handler calls */
39913 DUK_HEAP_SET_ERRHANDLER_RUNNING(thr->heap);
39914
11fdf7f2 39915 call_flags = DUK_CALL_FLAG_IGNORE_RECLIMIT; /* ignore reclimit, not constructor */
7c673cae 39916
11fdf7f2
TL
39917 rc = duk_handle_call_protected(thr,
39918 1, /* num args */
39919 call_flags); /* call_flags */
7c673cae
FG
39920 DUK_UNREF(rc); /* no need to check now: both success and error are OK */
39921
39922 DUK_ASSERT(DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap));
39923 DUK_HEAP_CLEAR_ERRHANDLER_RUNNING(thr->heap);
39924
39925 /* [ ... errval ] */
39926}
39927#endif /* DUK_USE_ERRTHROW || DUK_USE_ERRCREATE */
39928
39929/*
11fdf7f2 39930 * Add ._Tracedata to an error on the stack top.
7c673cae
FG
39931 */
39932
11fdf7f2 39933#if defined(DUK_USE_TRACEBACKS)
7c673cae
FG
39934DUK_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) {
39935 duk_context *ctx = (duk_context *) thr;
39936 duk_small_uint_t depth;
39937 duk_int_t i, i_min;
39938 duk_uarridx_t arr_idx;
39939 duk_double_t d;
39940
39941 DUK_ASSERT(thr != NULL);
39942 DUK_ASSERT(thr_callstack != NULL);
39943 DUK_ASSERT(ctx != NULL);
39944
39945 /* [ ... error ] */
39946
39947 /*
39948 * The traceback format is pretty arcane in an attempt to keep it compact
39949 * and cheap to create. It may change arbitrarily from version to version.
39950 * It should be decoded/accessed through version specific accessors only.
39951 *
39952 * See doc/error-objects.rst.
39953 */
39954
39955 DUK_DDD(DUK_DDDPRINT("adding traceback to object: %!T",
39956 (duk_tval *) duk_get_tval(ctx, -1)));
39957
39958 duk_push_array(ctx); /* XXX: specify array size, as we know it */
39959 arr_idx = 0;
39960
11fdf7f2
TL
39961 /* Compiler SyntaxErrors (and other errors) come first, and are
39962 * blamed by default (not flagged "noblame").
7c673cae
FG
39963 */
39964 if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) {
39965 duk_push_hstring(ctx, thr->compile_ctx->h_filename);
39966 duk_xdef_prop_index_wec(ctx, -2, arr_idx);
39967 arr_idx++;
39968
39969 duk_push_uint(ctx, (duk_uint_t) thr->compile_ctx->curr_token.start_line); /* (flags<<32) + (line), flags = 0 */
39970 duk_xdef_prop_index_wec(ctx, -2, arr_idx);
39971 arr_idx++;
39972 }
39973
11fdf7f2 39974 /* Filename/line from C macros (__FILE__, __LINE__) are added as an
7c673cae
FG
39975 * entry with a special format: (string, number). The number contains
39976 * the line and flags.
39977 */
39978
39979 /* XXX: optimize: allocate an array part to the necessary size (upwards
39980 * estimate) and fill in the values directly into the array part; finally
39981 * update 'length'.
39982 */
39983
39984 /* XXX: using duk_put_prop_index() would cause obscure error cases when Array.prototype
39985 * has write-protected array index named properties. This was seen as DoubleErrors
39986 * in e.g. some test262 test cases. Using duk_xdef_prop_index() is better but heavier.
11fdf7f2
TL
39987 * The best fix is to fill in the tracedata directly into the array part. There are
39988 * no side effect concerns if the array part is allocated directly and only INCREFs
39989 * happen after that.
7c673cae
FG
39990 */
39991
39992 /* [ ... error arr ] */
39993
39994 if (c_filename) {
39995 duk_push_string(ctx, c_filename);
39996 duk_xdef_prop_index_wec(ctx, -2, arr_idx);
39997 arr_idx++;
39998
39999 d = (noblame_fileline ? ((duk_double_t) DUK_TB_FLAG_NOBLAME_FILELINE) * DUK_DOUBLE_2TO32 : 0.0) +
40000 (duk_double_t) c_line;
40001 duk_push_number(ctx, d);
40002 duk_xdef_prop_index_wec(ctx, -2, arr_idx);
40003 arr_idx++;
40004 }
40005
40006 /* traceback depth doesn't take into account the filename/line
40007 * special handling above (intentional)
40008 */
40009 depth = DUK_USE_TRACEBACK_DEPTH;
40010 i_min = (thr_callstack->callstack_top > (duk_size_t) depth ? (duk_int_t) (thr_callstack->callstack_top - depth) : 0);
40011 DUK_ASSERT(i_min >= 0);
40012
40013 /* [ ... error arr ] */
40014
40015 DUK_ASSERT(thr_callstack->callstack_top <= DUK_INT_MAX); /* callstack limits */
40016 for (i = (duk_int_t) (thr_callstack->callstack_top - 1); i >= i_min; i--) {
40017 duk_uint32_t pc;
40018
40019 /*
40020 * Note: each API operation potentially resizes the callstack,
40021 * so be careful to re-lookup after every operation. Currently
40022 * these is no issue because we don't store a temporary 'act'
40023 * pointer at all. (This would be a non-issue if we operated
40024 * directly on the array part.)
40025 */
40026
40027 /* [... arr] */
40028
40029 DUK_ASSERT_DISABLE(thr_callstack->callstack[i].pc >= 0); /* unsigned */
40030
40031 /* Add function object. */
40032 duk_push_tval(ctx, &(thr_callstack->callstack + i)->tv_func);
40033 duk_xdef_prop_index_wec(ctx, -2, arr_idx);
40034 arr_idx++;
40035
40036 /* Add a number containing: pc, activation flags.
40037 *
40038 * PC points to next instruction, find offending PC. Note that
40039 * PC == 0 for native code.
40040 */
40041 pc = duk_hthread_get_act_prev_pc(thr_callstack, thr_callstack->callstack + i);
40042 DUK_ASSERT_DISABLE(pc >= 0); /* unsigned */
40043 DUK_ASSERT((duk_double_t) pc < DUK_DOUBLE_2TO32); /* assume PC is at most 32 bits and non-negative */
40044 d = ((duk_double_t) thr_callstack->callstack[i].flags) * DUK_DOUBLE_2TO32 + (duk_double_t) pc;
40045 duk_push_number(ctx, d); /* -> [... arr num] */
40046 duk_xdef_prop_index_wec(ctx, -2, arr_idx);
40047 arr_idx++;
40048 }
40049
40050 /* XXX: set with duk_hobject_set_length() when tracedata is filled directly */
40051 duk_push_uint(ctx, (duk_uint_t) arr_idx);
40052 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_WC);
40053
40054 /* [ ... error arr ] */
40055
40056 duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_INT_TRACEDATA); /* -> [ ... error ] */
40057}
40058#endif /* DUK_USE_TRACEBACKS */
40059
11fdf7f2
TL
40060/*
40061 * Add .fileName and .lineNumber to an error on the stack top.
40062 */
40063
40064#if !defined(DUK_USE_TRACEBACKS)
40065DUK_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) {
40066 duk_context *ctx;
40067#if defined(DUK_USE_ASSERTIONS)
7c673cae
FG
40068 duk_int_t entry_top;
40069#endif
40070
11fdf7f2
TL
40071 ctx = (duk_context *) thr;
40072#if defined(DUK_USE_ASSERTIONS)
7c673cae
FG
40073 entry_top = duk_get_top(ctx);
40074#endif
7c673cae 40075
7c673cae
FG
40076 /*
40077 * If tracebacks are disabled, 'fileName' and 'lineNumber' are added
40078 * as plain own properties. Since Error.prototype has accessors of
40079 * the same name, we need to define own properties directly (cannot
40080 * just use e.g. duk_put_prop_stridx). Existing properties are not
40081 * overwritten in case they already exist.
40082 */
40083
40084 if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) {
11fdf7f2
TL
40085 /* Compiler SyntaxError (or other error) gets the primary blame.
40086 * Currently no flag to prevent blaming.
40087 */
7c673cae 40088 duk_push_uint(ctx, (duk_uint_t) thr->compile_ctx->curr_token.start_line);
11fdf7f2 40089 duk_push_hstring(ctx, thr->compile_ctx->h_filename);
7c673cae 40090 } else if (c_filename && !noblame_fileline) {
11fdf7f2
TL
40091 /* C call site gets blamed next, unless flagged not to do so.
40092 * XXX: file/line is disabled in minimal builds, so disable this
40093 * too when appropriate.
7c673cae 40094 */
7c673cae 40095 duk_push_int(ctx, c_line);
11fdf7f2
TL
40096 duk_push_string(ctx, c_filename);
40097 } else {
40098 /* Finally, blame the innermost callstack entry which has a
40099 * .fileName property.
40100 */
40101 duk_small_uint_t depth;
40102 duk_int_t i, i_min;
40103 duk_uint32_t ecma_line;
7c673cae 40104
11fdf7f2
TL
40105 depth = DUK_USE_TRACEBACK_DEPTH;
40106 i_min = (thr_callstack->callstack_top > (duk_size_t) depth ? (duk_int_t) (thr_callstack->callstack_top - depth) : 0);
40107 DUK_ASSERT(i_min >= 0);
40108
40109 DUK_ASSERT(thr_callstack->callstack_top <= DUK_INT_MAX); /* callstack limits */
40110 for (i = (duk_int_t) (thr_callstack->callstack_top - 1); i >= i_min; i--) {
40111 duk_activation *act;
40112 duk_hobject *func;
7c673cae
FG
40113 duk_uint32_t pc;
40114
11fdf7f2
TL
40115 DUK_UNREF(pc);
40116 act = thr_callstack->callstack + i;
40117 DUK_ASSERT(act >= thr_callstack->callstack && act < thr_callstack->callstack + thr_callstack->callstack_size);
40118
40119 func = DUK_ACT_GET_FUNC(act);
40120 if (func == NULL) {
40121 /* Lightfunc, not blamed now. */
40122 continue;
40123 }
40124
40125 /* PC points to next instruction, find offending PC,
7c673cae
FG
40126 * PC == 0 for native code.
40127 */
11fdf7f2 40128 pc = duk_hthread_get_act_prev_pc(thr, act); /* thr argument only used for thr->heap, so specific thread doesn't matter */
7c673cae
FG
40129 DUK_ASSERT_DISABLE(pc >= 0); /* unsigned */
40130 DUK_ASSERT((duk_double_t) pc < DUK_DOUBLE_2TO32); /* assume PC is at most 32 bits and non-negative */
40131 act = NULL; /* invalidated by pushes, so get out of the way */
40132
40133 duk_push_hobject(ctx, func);
40134
40135 /* [ ... error func ] */
40136
40137 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_FILE_NAME);
11fdf7f2
TL
40138 if (!duk_is_string(ctx, -1)) {
40139 duk_pop_2(ctx);
40140 continue;
40141 }
40142
40143 /* [ ... error func fileName ] */
7c673cae 40144
11fdf7f2 40145 ecma_line = 0;
7c673cae
FG
40146#if defined(DUK_USE_PC2LINE)
40147 if (DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
11fdf7f2 40148 ecma_line = duk_hobject_pc2line_query(ctx, -2, (duk_uint_fast32_t) pc);
7c673cae
FG
40149 } else {
40150 /* Native function, no relevant lineNumber. */
40151 }
40152#endif /* DUK_USE_PC2LINE */
11fdf7f2 40153 duk_push_u32(ctx, ecma_line);
7c673cae 40154
11fdf7f2
TL
40155 /* [ ... error func fileName lineNumber ] */
40156
40157 duk_replace(ctx, -3);
40158
40159 /* [ ... error lineNumber fileName ] */
40160 goto define_props;
7c673cae 40161 }
11fdf7f2
TL
40162
40163 /* No activation matches, use undefined for both .fileName and
40164 * .lineNumber (matches what we do with a _Tracedata based
40165 * no-match lookup.
40166 */
40167 duk_push_undefined(ctx);
40168 duk_push_undefined(ctx);
7c673cae 40169 }
7c673cae 40170
11fdf7f2
TL
40171 define_props:
40172 /* [ ... error lineNumber fileName ] */
40173#if defined(DUK_USE_ASSERTIONS)
40174 DUK_ASSERT(duk_get_top(ctx) == entry_top + 2);
40175#endif
40176 duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE);
40177 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LINE_NUMBER, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE);
40178}
40179#endif /* !DUK_USE_TRACEBACKS */
40180
40181/*
40182 * Add line number to a compiler error.
40183 */
40184
40185DUK_LOCAL void duk__add_compiler_error_line(duk_hthread *thr) {
40186 duk_context *ctx;
40187
40188 /* Append a "(line NNN)" to the "message" property of any error
40189 * thrown during compilation. Usually compilation errors are
40190 * SyntaxErrors but they can also be out-of-memory errors and
40191 * the like.
40192 */
40193
40194 /* [ ... error ] */
40195
40196 ctx = (duk_context *) thr;
40197 DUK_ASSERT(duk_is_object(ctx, -1));
40198
40199 if (!(thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL)) {
40200 return;
40201 }
40202
40203 DUK_DDD(DUK_DDDPRINT("compile error, before adding line info: %!T",
40204 (duk_tval *) duk_get_tval(ctx, -1)));
40205
40206 if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_MESSAGE)) {
40207 duk_push_sprintf(ctx, " (line %ld)", (long) thr->compile_ctx->curr_token.start_line);
40208 duk_concat(ctx, 2);
40209 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE);
40210 } else {
40211 duk_pop(ctx);
40212 }
40213
40214 DUK_DDD(DUK_DDDPRINT("compile error, after adding line info: %!T",
40215 (duk_tval *) duk_get_tval(ctx, -1)));
40216}
40217
40218/*
40219 * Augment an error being created using Duktape specific properties
40220 * like _Tracedata or .fileName/.lineNumber.
40221 */
40222
40223#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
40224DUK_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) {
40225 duk_context *ctx = (duk_context *) thr;
40226#if defined(DUK_USE_ASSERTIONS)
40227 duk_int_t entry_top;
40228#endif
40229
40230#if defined(DUK_USE_ASSERTIONS)
40231 entry_top = duk_get_top(ctx);
40232#endif
40233 DUK_ASSERT(obj != NULL);
40234
40235 DUK_UNREF(obj); /* unreferenced w/o tracebacks */
40236 DUK_UNREF(ctx); /* unreferenced w/o asserts */
40237
40238 duk__add_compiler_error_line(thr);
40239
40240#if defined(DUK_USE_TRACEBACKS)
40241 /* If tracebacks are enabled, the '_Tracedata' property is the only
40242 * thing we need: 'fileName' and 'lineNumber' are virtual properties
40243 * which use '_Tracedata'.
40244 */
40245 if (duk_hobject_hasprop_raw(thr, obj, DUK_HTHREAD_STRING_INT_TRACEDATA(thr))) {
40246 DUK_DDD(DUK_DDDPRINT("error value already has a '_Tracedata' property, not modifying it"));
40247 } else {
40248 duk__add_traceback(thr, thr_callstack, c_filename, c_line, noblame_fileline);
40249 }
40250#else
40251 /* Without tracebacks the concrete .fileName and .lineNumber need
40252 * to be added directly.
40253 */
40254 duk__add_fileline(thr, thr_callstack, c_filename, c_line, noblame_fileline);
40255#endif
40256
40257#if defined(DUK_USE_ASSERTIONS)
7c673cae
FG
40258 DUK_ASSERT(duk_get_top(ctx) == entry_top);
40259#endif
40260}
40261#endif /* DUK_USE_AUGMENT_ERROR_CREATE */
40262
40263/*
40264 * Augment an error at creation time with _Tracedata/fileName/lineNumber
40265 * and allow a user error handler (if defined) to process/replace the error.
40266 * The error to be augmented is at the stack top.
40267 *
40268 * thr: thread containing the error value
40269 * thr_callstack: thread which should be used for generating callstack etc.
40270 * c_filename: C __FILE__ related to the error
40271 * c_line: C __LINE__ related to the error
40272 * noblame_fileline: if true, don't fileName/line as error source, otherwise use traceback
40273 * (needed because user code filename/line are reported but internal ones
40274 * are not)
40275 *
40276 * XXX: rename noblame_fileline to flags field; combine it to some existing
40277 * field (there are only a few call sites so this may not be worth it).
40278 */
40279
40280#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
40281DUK_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) {
40282 duk_context *ctx = (duk_context *) thr;
40283 duk_hobject *obj;
40284
40285 DUK_ASSERT(thr != NULL);
40286 DUK_ASSERT(thr_callstack != NULL);
40287 DUK_ASSERT(ctx != NULL);
40288
40289 /* [ ... error ] */
40290
40291 /*
40292 * Criteria for augmenting:
40293 *
40294 * - augmentation enabled in build (naturally)
40295 * - error value internal prototype chain contains the built-in
40296 * Error prototype object (i.e. 'val instanceof Error')
40297 *
40298 * Additional criteria for built-in augmenting:
40299 *
40300 * - error value is an extensible object
40301 */
40302
40303 obj = duk_get_hobject(ctx, -1);
40304 if (!obj) {
40305 DUK_DDD(DUK_DDDPRINT("value is not an object, skip both built-in and user augment"));
40306 return;
40307 }
40308 if (!duk_hobject_prototype_chain_contains(thr, obj, thr->builtins[DUK_BIDX_ERROR_PROTOTYPE], 1 /*ignore_loop*/)) {
40309 /* If the value has a prototype loop, it's critical not to
40310 * throw here. Instead, assume the value is not to be
40311 * augmented.
40312 */
40313 DUK_DDD(DUK_DDDPRINT("value is not an error instance, skip both built-in and user augment"));
40314 return;
40315 }
40316 if (DUK_HOBJECT_HAS_EXTENSIBLE(obj)) {
40317 DUK_DDD(DUK_DDDPRINT("error meets criteria, built-in augment"));
11fdf7f2 40318 duk__err_augment_builtin_create(thr, thr_callstack, c_filename, c_line, noblame_fileline, obj);
7c673cae
FG
40319 } else {
40320 DUK_DDD(DUK_DDDPRINT("error does not meet criteria, no built-in augment"));
40321 }
40322
40323 /* [ ... error ] */
40324
40325#if defined(DUK_USE_ERRCREATE)
40326 duk__err_augment_user(thr, DUK_STRIDX_ERR_CREATE);
40327#endif
40328}
40329#endif /* DUK_USE_AUGMENT_ERROR_CREATE */
40330
40331/*
40332 * Augment an error at throw time; allow a user error handler (if defined)
40333 * to process/replace the error. The error to be augmented is at the
40334 * stack top.
40335 */
40336
40337#if defined(DUK_USE_AUGMENT_ERROR_THROW)
40338DUK_INTERNAL void duk_err_augment_error_throw(duk_hthread *thr) {
40339#if defined(DUK_USE_ERRTHROW)
40340 duk__err_augment_user(thr, DUK_STRIDX_ERR_THROW);
40341#endif /* DUK_USE_ERRTHROW */
40342}
40343#endif /* DUK_USE_AUGMENT_ERROR_THROW */
7c673cae
FG
40344/*
40345 * Do a longjmp call, calling the fatal error handler if no
40346 * catchpoint exists.
40347 */
40348
40349/* include removed: duk_internal.h */
40350
40351DUK_INTERNAL void duk_err_longjmp(duk_hthread *thr) {
40352 DUK_ASSERT(thr != NULL);
40353
11fdf7f2
TL
40354 DUK_DD(DUK_DDPRINT("longjmp error: type=%d iserror=%d value1=%!T value2=%!T",
40355 (int) thr->heap->lj.type, (int) thr->heap->lj.iserror,
40356 &thr->heap->lj.value1, &thr->heap->lj.value2));
40357
40358#if !defined(DUK_USE_CPP_EXCEPTIONS)
40359 /* If we don't have a jmpbuf_ptr, there is little we can do
40360 * except panic. The caller's expectation is that we never
40361 * return.
40362 *
40363 * With C++ exceptions we now just propagate an uncaught error
40364 * instead of invoking the fatal error handler. Because there's
40365 * a dummy jmpbuf for C++ exceptions now, this could be changed.
40366 */
7c673cae 40367 if (!thr->heap->lj.jmpbuf_ptr) {
7c673cae
FG
40368
40369 DUK_D(DUK_DPRINT("uncaught error: type=%d iserror=%d value1=%!T value2=%!T",
40370 (int) thr->heap->lj.type, (int) thr->heap->lj.iserror,
40371 &thr->heap->lj.value1, &thr->heap->lj.value2));
40372
40373 duk_fatal((duk_context *) thr, DUK_ERR_UNCAUGHT_ERROR, "uncaught error");
40374 DUK_UNREACHABLE();
40375 }
11fdf7f2 40376#endif /* DUK_USE_CPP_EXCEPTIONS */
7c673cae 40377
11fdf7f2
TL
40378#if defined(DUK_USE_CPP_EXCEPTIONS)
40379 {
40380 duk_internal_exception exc; /* dummy */
40381 throw exc;
40382 }
40383#else /* DUK_USE_CPP_EXCEPTIONS */
7c673cae 40384 DUK_LONGJMP(thr->heap->lj.jmpbuf_ptr->jb);
11fdf7f2
TL
40385#endif /* DUK_USE_CPP_EXCEPTIONS */
40386
7c673cae
FG
40387 DUK_UNREACHABLE();
40388}
7c673cae
FG
40389/*
40390 * Error helpers
40391 */
40392
40393/* include removed: duk_internal.h */
40394
11fdf7f2
TL
40395/*
40396 * Helper to walk the thread chain and see if there is an active error
40397 * catcher. Protected calls or finally blocks aren't considered catching.
40398 */
40399
40400#if defined(DUK_USE_DEBUGGER_SUPPORT) && \
40401 (defined(DUK_USE_DEBUGGER_THROW_NOTIFY) || defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT))
40402DUK_LOCAL duk_bool_t duk__have_active_catcher(duk_hthread *thr) {
40403 /*
40404 * XXX: As noted above, a protected API call won't be counted as a
40405 * catcher. This is usually convenient, e.g. in the case of a top-
40406 * level duk_pcall(), but may not always be desirable. Perhaps add an
40407 * argument to treat them as catchers?
40408 */
40409
40410 duk_size_t i;
40411
40412 DUK_ASSERT(thr != NULL);
40413
40414 while (thr != NULL) {
40415 for (i = 0; i < thr->catchstack_top; i++) {
40416 duk_catcher *cat = thr->catchstack + i;
40417 if (DUK_CAT_HAS_CATCH_ENABLED(cat)) {
40418 return 1; /* all we need to know */
40419 }
40420 }
40421 thr = thr->resumer;
40422 }
40423 return 0;
40424}
40425#endif /* DUK_USE_DEBUGGER_SUPPORT && (DUK_USE_DEBUGGER_THROW_NOTIFY || DUK_USE_DEBUGGER_PAUSE_UNCAUGHT) */
40426
7c673cae
FG
40427/*
40428 * Get prototype object for an integer error code.
40429 */
40430
40431DUK_INTERNAL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, duk_errcode_t code) {
40432 switch (code) {
40433 case DUK_ERR_EVAL_ERROR:
40434 return thr->builtins[DUK_BIDX_EVAL_ERROR_PROTOTYPE];
40435 case DUK_ERR_RANGE_ERROR:
40436 return thr->builtins[DUK_BIDX_RANGE_ERROR_PROTOTYPE];
40437 case DUK_ERR_REFERENCE_ERROR:
40438 return thr->builtins[DUK_BIDX_REFERENCE_ERROR_PROTOTYPE];
40439 case DUK_ERR_SYNTAX_ERROR:
40440 return thr->builtins[DUK_BIDX_SYNTAX_ERROR_PROTOTYPE];
40441 case DUK_ERR_TYPE_ERROR:
40442 return thr->builtins[DUK_BIDX_TYPE_ERROR_PROTOTYPE];
40443 case DUK_ERR_URI_ERROR:
40444 return thr->builtins[DUK_BIDX_URI_ERROR_PROTOTYPE];
40445
40446 /* XXX: more specific error classes? */
40447 case DUK_ERR_UNIMPLEMENTED_ERROR:
40448 case DUK_ERR_INTERNAL_ERROR:
40449 case DUK_ERR_ALLOC_ERROR:
40450 case DUK_ERR_ASSERTION_ERROR:
40451 case DUK_ERR_API_ERROR:
40452 case DUK_ERR_ERROR:
40453 default:
40454 return thr->builtins[DUK_BIDX_ERROR_PROTOTYPE];
40455 }
40456}
40457
40458/*
40459 * Exposed helper for setting up heap longjmp state.
40460 */
40461
40462DUK_INTERNAL void duk_err_setup_heap_ljstate(duk_hthread *thr, duk_small_int_t lj_type) {
11fdf7f2
TL
40463#if defined(DUK_USE_DEBUGGER_SUPPORT)
40464 /* If something is thrown with the debugger attached and nobody will
40465 * catch it, execution is paused before the longjmp, turning over
40466 * control to the debug client. This allows local state to be examined
40467 * before the stack is unwound. Errors are not intercepted when debug
40468 * message loop is active (e.g. for Eval).
40469 */
40470
40471 /* XXX: Allow customizing the pause and notify behavior at runtime
40472 * using debugger runtime flags. For now the behavior is fixed using
40473 * config options.
40474 */
40475#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY) || defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT)
40476 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap) &&
40477 !thr->heap->dbg_processing &&
40478 lj_type == DUK_LJ_TYPE_THROW) {
40479 duk_context *ctx = (duk_context *) thr;
40480 duk_bool_t fatal;
40481 duk_hobject *h_obj;
40482
40483 /* Don't intercept a DoubleError, we may have caused the initial double
40484 * fault and attempting to intercept it will cause us to be called
40485 * recursively and exhaust the C stack.
40486 */
40487 h_obj = duk_get_hobject(ctx, -1);
40488 if (h_obj == thr->builtins[DUK_BIDX_DOUBLE_ERROR]) {
40489 DUK_D(DUK_DPRINT("built-in DoubleError instance thrown, not intercepting"));
40490 goto skip_throw_intercept;
40491 }
40492
40493 DUK_D(DUK_DPRINT("throw with debugger attached, report to client"));
40494
40495 fatal = !duk__have_active_catcher(thr);
40496
40497#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY)
40498 /* Report it to the debug client */
40499 duk_debug_send_throw(thr, fatal);
40500#endif
40501
40502#if defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT)
40503 if (fatal) {
40504 DUK_D(DUK_DPRINT("throw will be fatal, halt before longjmp"));
40505 duk_debug_halt_execution(thr, 1 /*use_prev_pc*/);
40506 }
40507#endif
40508 }
40509
40510 skip_throw_intercept:
40511#endif /* DUK_USE_DEBUGGER_THROW_NOTIFY || DUK_USE_DEBUGGER_PAUSE_UNCAUGHT */
40512#endif /* DUK_USE_DEBUGGER_SUPPORT */
7c673cae
FG
40513
40514 thr->heap->lj.type = lj_type;
40515
40516 DUK_ASSERT(thr->valstack_top > thr->valstack);
11fdf7f2 40517 DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, thr->valstack_top - 1); /* side effects */
7c673cae
FG
40518
40519 duk_pop((duk_context *) thr);
40520}
7c673cae
FG
40521/*
40522 * Create and throw an Ecmascript error object based on a code and a message.
40523 *
40524 * Used when we throw errors internally. Ecmascript generated error objects
40525 * are created by Ecmascript code, and the throwing is handled by the bytecode
40526 * executor.
40527 */
40528
40529/* include removed: duk_internal.h */
40530
40531/*
40532 * Create and throw an error (originating from Duktape internally)
40533 *
40534 * Push an error object on top of the stack, possibly throw augmenting
40535 * the error, and finally longjmp.
40536 *
40537 * If an error occurs while we're dealing with the current error, we might
40538 * enter an infinite recursion loop. This is prevented by detecting a
40539 * "double fault" through the heap->handling_error flag; the recursion
40540 * then stops at the second level.
40541 */
40542
40543#ifdef DUK_USE_VERBOSE_ERRORS
40544DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code, const char *msg, const char *filename, duk_int_t line) {
40545#else
40546DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code) {
40547#endif
40548 duk_context *ctx = (duk_context *) thr;
40549 duk_bool_t double_error = thr->heap->handling_error;
40550
40551#ifdef DUK_USE_VERBOSE_ERRORS
40552 DUK_DD(DUK_DDPRINT("duk_err_create_and_throw(): code=%ld, msg=%s, filename=%s, line=%ld",
40553 (long) code, (const char *) msg,
40554 (const char *) filename, (long) line));
40555#else
40556 DUK_DD(DUK_DDPRINT("duk_err_create_and_throw(): code=%ld", (long) code));
40557#endif
40558
40559 DUK_ASSERT(thr != NULL);
40560 DUK_ASSERT(ctx != NULL);
40561
40562 thr->heap->handling_error = 1;
40563
40564 if (!double_error) {
40565 /* Allow headroom for calls during error handling (see GH-191).
40566 * We allow space for 10 additional recursions, with one extra
40567 * for, e.g. a print() call at the deepest level.
40568 */
40569 DUK_ASSERT(thr->callstack_max == DUK_CALLSTACK_DEFAULT_MAX);
40570 thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX + DUK_CALLSTACK_GROW_STEP + 11;
40571 }
40572
40573 DUK_ASSERT(thr->callstack_max == DUK_CALLSTACK_DEFAULT_MAX + DUK_CALLSTACK_GROW_STEP + 11); /* just making sure */
40574
40575 /* Sync so that augmentation sees up-to-date activations, NULL
40576 * thr->ptr_curr_pc so that it's not used if side effects occur
40577 * in augmentation or longjmp handling.
40578 */
40579 duk_hthread_sync_and_null_currpc(thr);
40580
40581 /*
40582 * Create and push an error object onto the top of stack.
40583 * If a "double error" occurs, use a fixed error instance
40584 * to avoid further trouble.
40585 */
40586
40587 /* XXX: if attempt to push beyond allocated valstack, this double fault
40588 * handling fails miserably. We should really write the double error
40589 * directly to thr->heap->lj.value1 and avoid valstack use entirely.
40590 */
40591
40592 if (double_error) {
40593 if (thr->builtins[DUK_BIDX_DOUBLE_ERROR]) {
40594 DUK_D(DUK_DPRINT("double fault detected -> push built-in fixed 'double error' instance"));
40595 duk_push_hobject_bidx(ctx, DUK_BIDX_DOUBLE_ERROR);
40596 } else {
40597 DUK_D(DUK_DPRINT("double fault detected; there is no built-in fixed 'double error' instance "
40598 "-> push the error code as a number"));
40599 duk_push_int(ctx, (duk_int_t) code);
40600 }
40601 } else {
40602 /* Error object is augmented at its creation here. */
40603 duk_require_stack(ctx, 1);
40604 /* XXX: unnecessary '%s' formatting here, but cannot use
40605 * 'msg' as a format string directly.
40606 */
40607#ifdef DUK_USE_VERBOSE_ERRORS
40608 duk_push_error_object_raw(ctx,
40609 code | DUK_ERRCODE_FLAG_NOBLAME_FILELINE,
40610 filename,
40611 line,
40612 "%s",
40613 (const char *) msg);
40614#else
40615 duk_push_error_object_raw(ctx,
40616 code | DUK_ERRCODE_FLAG_NOBLAME_FILELINE,
40617 NULL,
40618 0,
40619 NULL);
40620#endif
40621 }
40622
40623 /*
40624 * Augment error (throw time), unless alloc/double error
40625 */
40626
40627 if (double_error || code == DUK_ERR_ALLOC_ERROR) {
40628 DUK_D(DUK_DPRINT("alloc or double error: skip throw augmenting to avoid further trouble"));
40629 } else {
40630#if defined(DUK_USE_AUGMENT_ERROR_THROW)
40631 DUK_DDD(DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT (before throw augment)",
40632 (duk_tval *) duk_get_tval(ctx, -1)));
40633 duk_err_augment_error_throw(thr);
40634#endif
40635 }
40636
40637 /*
40638 * Finally, longjmp
40639 */
40640
40641 duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW);
40642
40643 thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX; /* reset callstack limit */
40644 thr->heap->handling_error = 0;
40645
40646 DUK_DDD(DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT, %!iT (after throw augment)",
40647 (duk_tval *) &thr->heap->lj.value1, (duk_tval *) &thr->heap->lj.value2));
40648
40649 duk_err_longjmp(thr);
40650 DUK_UNREACHABLE();
40651}
40652
40653/*
40654 * Helper for C function call negative return values.
40655 */
40656
40657DUK_INTERNAL void duk_error_throw_from_negative_rc(duk_hthread *thr, duk_ret_t rc) {
40658 duk_context *ctx = (duk_context *) thr;
40659 const char *msg;
40660 duk_errcode_t code;
40661
40662 DUK_ASSERT(thr != NULL);
40663 DUK_ASSERT(rc < 0);
40664
40665 /* XXX: this generates quite large code - perhaps select the error
40666 * class based on the code and then just use the error 'name'?
40667 */
40668 /* XXX: shared strings */
40669
40670 code = -rc;
40671
40672 switch (rc) {
40673 case DUK_RET_UNIMPLEMENTED_ERROR: msg = "unimplemented"; break;
40674 case DUK_RET_UNSUPPORTED_ERROR: msg = "unsupported"; break;
40675 case DUK_RET_INTERNAL_ERROR: msg = "internal"; break;
40676 case DUK_RET_ALLOC_ERROR: msg = "alloc"; break;
40677 case DUK_RET_ASSERTION_ERROR: msg = "assertion"; break;
40678 case DUK_RET_API_ERROR: msg = "api"; break;
40679 case DUK_RET_UNCAUGHT_ERROR: msg = "uncaught"; break;
40680 case DUK_RET_ERROR: msg = "error"; break;
40681 case DUK_RET_EVAL_ERROR: msg = "eval"; break;
40682 case DUK_RET_RANGE_ERROR: msg = "range"; break;
40683 case DUK_RET_REFERENCE_ERROR: msg = "reference"; break;
40684 case DUK_RET_SYNTAX_ERROR: msg = "syntax"; break;
40685 case DUK_RET_TYPE_ERROR: msg = "type"; break;
40686 case DUK_RET_URI_ERROR: msg = "uri"; break;
40687 default: msg = "unknown"; break;
40688 }
40689
40690 DUK_ASSERT(msg != NULL);
40691
40692 /*
40693 * The __FILE__ and __LINE__ information is intentionally not used in the
40694 * creation of the error object, as it isn't useful in the tracedata. The
40695 * tracedata still contains the function which returned the negative return
40696 * code, and having the file/line of this function isn't very useful.
40697 */
40698
40699 duk_error_raw(ctx, code, NULL, 0, "%s error (rc %ld)", (const char *) msg, (long) rc);
40700 DUK_UNREACHABLE();
40701}
7c673cae
FG
40702/*
40703 * duk_hbuffer allocation and freeing.
40704 */
40705
40706/* include removed: duk_internal.h */
40707
40708/* Allocate a new duk_hbuffer of a certain type and return a pointer to it
40709 * (NULL on error). Write buffer data pointer to 'out_bufdata' (only if
40710 * allocation successful).
40711 */
40712DUK_INTERNAL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk_small_uint_t flags, void **out_bufdata) {
40713 duk_hbuffer *res = NULL;
40714 duk_size_t header_size;
40715 duk_size_t alloc_size;
40716
40717 DUK_ASSERT(heap != NULL);
40718 DUK_ASSERT(out_bufdata != NULL);
40719
40720 DUK_DDD(DUK_DDDPRINT("allocate hbuffer"));
40721
40722 /* Size sanity check. Should not be necessary because caller is
40723 * required to check this, but we don't want to cause a segfault
40724 * if the size wraps either in duk_size_t computation or when
40725 * storing the size in a 16-bit field.
40726 */
40727 if (size > DUK_HBUFFER_MAX_BYTELEN) {
40728 DUK_D(DUK_DPRINT("hbuffer alloc failed: size too large: %ld", (long) size));
40729 return NULL; /* no need to write 'out_bufdata' */
40730 }
40731
40732 if (flags & DUK_BUF_FLAG_EXTERNAL) {
40733 header_size = sizeof(duk_hbuffer_external);
40734 alloc_size = sizeof(duk_hbuffer_external);
11fdf7f2 40735 } else if (flags & DUK_BUF_FLAG_DYNAMIC) {
7c673cae
FG
40736 header_size = sizeof(duk_hbuffer_dynamic);
40737 alloc_size = sizeof(duk_hbuffer_dynamic);
40738 } else {
40739 header_size = sizeof(duk_hbuffer_fixed);
40740 alloc_size = sizeof(duk_hbuffer_fixed) + size;
40741 DUK_ASSERT(alloc_size >= sizeof(duk_hbuffer_fixed)); /* no wrapping */
40742 }
40743
40744 res = (duk_hbuffer *) DUK_ALLOC(heap, alloc_size);
40745 if (!res) {
40746 goto error;
40747 }
40748
40749 /* zero everything unless requested not to do so */
40750#if defined(DUK_USE_ZERO_BUFFER_DATA)
40751 DUK_MEMZERO((void *) res,
40752 (flags & DUK_BUF_FLAG_NOZERO) ? header_size : alloc_size);
40753#else
40754 DUK_MEMZERO((void *) res, header_size);
40755#endif
40756
40757 if (flags & DUK_BUF_FLAG_EXTERNAL) {
40758 duk_hbuffer_external *h;
40759 h = (duk_hbuffer_external *) res;
40760 DUK_UNREF(h);
40761 *out_bufdata = NULL;
40762#if defined(DUK_USE_EXPLICIT_NULL_INIT)
40763#if defined(DUK_USE_HEAPPTR16)
40764/* the compressed pointer is zeroed which maps to NULL, so nothing to do. */
40765#else
40766 DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap, h, NULL);
40767#endif
40768#endif
40769 DUK_ASSERT(DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap, h) == NULL);
40770 } else if (flags & DUK_BUF_FLAG_DYNAMIC) {
40771 duk_hbuffer_dynamic *h = (duk_hbuffer_dynamic *) res;
40772 void *ptr;
40773
40774 if (size > 0) {
40775 DUK_ASSERT(!(flags & DUK_BUF_FLAG_EXTERNAL)); /* alloc external with size zero */
40776 DUK_DDD(DUK_DDDPRINT("dynamic buffer with nonzero size, alloc actual buffer"));
40777#ifdef DUK_USE_ZERO_BUFFER_DATA
40778 ptr = DUK_ALLOC_ZEROED(heap, size);
40779#else
40780 ptr = DUK_ALLOC(heap, size);
40781#endif
40782 if (!ptr) {
40783 /* Because size > 0, NULL check is correct */
40784 goto error;
40785 }
40786 *out_bufdata = ptr;
40787
40788 DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap, h, ptr);
40789 } else {
40790 *out_bufdata = NULL;
40791#if defined(DUK_USE_EXPLICIT_NULL_INIT)
40792#if defined(DUK_USE_HEAPPTR16)
40793/* the compressed pointer is zeroed which maps to NULL, so nothing to do. */
40794#else
40795 DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap, h, NULL);
40796#endif
40797#endif
40798 DUK_ASSERT(DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, h) == NULL);
40799 }
40800 } else {
40801 *out_bufdata = (void *) ((duk_hbuffer_fixed *) res + 1);
40802 }
40803
40804 DUK_HBUFFER_SET_SIZE(res, size);
40805
40806 DUK_HEAPHDR_SET_TYPE(&res->hdr, DUK_HTYPE_BUFFER);
40807 if (flags & DUK_BUF_FLAG_DYNAMIC) {
40808 DUK_HBUFFER_SET_DYNAMIC(res);
40809 if (flags & DUK_BUF_FLAG_EXTERNAL) {
40810 DUK_HBUFFER_SET_EXTERNAL(res);
40811 }
40812 } else {
40813 DUK_ASSERT(!(flags & DUK_BUF_FLAG_EXTERNAL));
40814 }
40815 DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &res->hdr);
40816
40817 DUK_DDD(DUK_DDDPRINT("allocated hbuffer: %p", (void *) res));
40818 return res;
40819
40820 error:
40821 DUK_DD(DUK_DDPRINT("hbuffer allocation failed"));
40822
40823 DUK_FREE(heap, res);
40824 return NULL; /* no need to write 'out_bufdata' */
40825}
40826
40827/* For indirect allocs. */
40828
40829DUK_INTERNAL void *duk_hbuffer_get_dynalloc_ptr(duk_heap *heap, void *ud) {
40830 duk_hbuffer_dynamic *buf = (duk_hbuffer_dynamic *) ud;
40831 DUK_UNREF(heap);
40832 return (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, buf);
40833}
7c673cae
FG
40834/*
40835 * duk_hbuffer operations such as resizing and inserting/appending data to
40836 * a dynamic buffer.
40837 *
40838 * Append operations append to the end of the buffer and they are relatively
40839 * efficient: the buffer is grown with a "spare" part relative to the buffer
40840 * size to minimize reallocations. Insert operations need to move existing
40841 * data forward in the buffer with memmove() and are not very efficient.
40842 * They are used e.g. by the regexp compiler to "backpatch" regexp bytecode.
40843 */
40844
40845/* include removed: duk_internal.h */
40846
40847/*
40848 * Resizing
40849 */
40850
40851DUK_INTERNAL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_size_t new_size) {
40852 void *res;
40853 duk_size_t prev_size;
40854
40855 DUK_ASSERT(thr != NULL);
40856 DUK_ASSERT(buf != NULL);
40857 DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
40858 DUK_ASSERT(!DUK_HBUFFER_HAS_EXTERNAL(buf));
40859
40860 /*
40861 * Maximum size check
40862 */
40863
40864 if (new_size > DUK_HBUFFER_MAX_BYTELEN) {
11fdf7f2 40865 DUK_ERROR_RANGE(thr, "buffer too long");
7c673cae
FG
40866 }
40867
40868 /*
40869 * Note: use indirect realloc variant just in case mark-and-sweep
40870 * (finalizers) might resize this same buffer during garbage
40871 * collection.
40872 */
40873
40874 res = DUK_REALLOC_INDIRECT(thr->heap, duk_hbuffer_get_dynalloc_ptr, (void *) buf, new_size);
40875 if (res != NULL || new_size == 0) {
40876 /* 'res' may be NULL if new allocation size is 0. */
40877
40878 DUK_DDD(DUK_DDDPRINT("resized dynamic buffer %p:%ld -> %p:%ld",
40879 (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, buf),
40880 (long) DUK_HBUFFER_DYNAMIC_GET_SIZE(buf),
40881 (void *) res,
40882 (long) new_size));
40883
40884 /*
40885 * The entire allocated buffer area, regardless of actual used
40886 * size, is kept zeroed in resizes for simplicity. If the buffer
40887 * is grown, zero the new part.
40888 */
40889
40890 prev_size = DUK_HBUFFER_DYNAMIC_GET_SIZE(buf);
40891 if (new_size > prev_size) {
40892 DUK_ASSERT(new_size - prev_size > 0);
40893#ifdef DUK_USE_ZERO_BUFFER_DATA
40894 DUK_MEMZERO((void *) ((char *) res + prev_size),
40895 (duk_size_t) (new_size - prev_size));
40896#endif
40897 }
40898
40899 DUK_HBUFFER_DYNAMIC_SET_SIZE(buf, new_size);
40900 DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(thr->heap, buf, res);
40901 } else {
11fdf7f2 40902 DUK_ERROR_ALLOC_DEFMSG(thr);
7c673cae
FG
40903 }
40904
40905 DUK_ASSERT(res != NULL || new_size == 0);
40906}
40907
40908DUK_INTERNAL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *buf) {
40909 DUK_ASSERT(thr != NULL);
40910 DUK_ASSERT(buf != NULL);
40911 DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
40912 DUK_ASSERT(!DUK_HBUFFER_HAS_EXTERNAL(buf));
40913
40914 duk_hbuffer_resize(thr, buf, 0);
40915}
40916/* include removed: duk_internal.h */
7c673cae
FG
40917
40918#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
40919DUK_INTERNAL duk_uint_t duk_hbufferobject_clamp_bytelength(duk_hbufferobject *h_bufobj, duk_uint_t len) {
40920 duk_uint_t buf_size;
40921 duk_uint_t buf_avail;
40922
40923 DUK_ASSERT(h_bufobj != NULL);
40924 DUK_ASSERT(h_bufobj->buf != NULL);
40925
40926 buf_size = (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_bufobj->buf);
40927 if (h_bufobj->offset > buf_size) {
40928 /* Slice starting point is beyond current length. */
40929 return 0;
40930 }
40931 buf_avail = buf_size - h_bufobj->offset;
40932
40933 return buf_avail >= len ? len : buf_avail;
40934}
40935#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
7c673cae
FG
40936/*
40937 * duk_heap allocation and freeing.
40938 */
40939
40940/* include removed: duk_internal.h */
40941
11fdf7f2 40942/* Constants for built-in string data depacking. */
7c673cae
FG
40943#define DUK__BITPACK_LETTER_LIMIT 26
40944#define DUK__BITPACK_UNDERSCORE 26
40945#define DUK__BITPACK_FF 27
40946#define DUK__BITPACK_SWITCH1 29
40947#define DUK__BITPACK_SWITCH 30
40948#define DUK__BITPACK_SEVENBIT 31
40949
11fdf7f2
TL
40950#if defined(DUK_USE_ROM_STRINGS)
40951/* Fixed seed value used with ROM strings. */
40952#define DUK__FIXED_HASH_SEED 0xabcd1234
40953#endif
40954
7c673cae
FG
40955/*
40956 * Free a heap object.
40957 *
40958 * Free heap object and its internal (non-heap) pointers. Assumes that
40959 * caller has removed the object from heap allocated list or the string
40960 * intern table, and any weak references (which strings may have) have
40961 * been already dealt with.
40962 */
40963
40964DUK_INTERNAL void duk_free_hobject_inner(duk_heap *heap, duk_hobject *h) {
40965 DUK_ASSERT(heap != NULL);
40966 DUK_ASSERT(h != NULL);
40967
40968 DUK_FREE(heap, DUK_HOBJECT_GET_PROPS(heap, h));
40969
40970 if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
40971 duk_hcompiledfunction *f = (duk_hcompiledfunction *) h;
40972 DUK_UNREF(f);
40973 /* Currently nothing to free; 'data' is a heap object */
40974 } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
40975 duk_hnativefunction *f = (duk_hnativefunction *) h;
40976 DUK_UNREF(f);
40977 /* Currently nothing to free */
40978 } else if (DUK_HOBJECT_IS_THREAD(h)) {
40979 duk_hthread *t = (duk_hthread *) h;
40980 DUK_FREE(heap, t->valstack);
40981 DUK_FREE(heap, t->callstack);
40982 DUK_FREE(heap, t->catchstack);
40983 /* Don't free h->resumer because it exists in the heap.
40984 * Callstack entries also contain function pointers which
40985 * are not freed for the same reason.
40986 */
40987
40988 /* XXX: with 'caller' property the callstack would need
40989 * to be unwound to update the 'caller' properties of
40990 * functions in the callstack.
40991 */
40992 }
40993}
40994
40995DUK_INTERNAL void duk_free_hbuffer_inner(duk_heap *heap, duk_hbuffer *h) {
40996 DUK_ASSERT(heap != NULL);
40997 DUK_ASSERT(h != NULL);
40998
40999 if (DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h)) {
41000 duk_hbuffer_dynamic *g = (duk_hbuffer_dynamic *) h;
41001 DUK_DDD(DUK_DDDPRINT("free dynamic buffer %p", (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, g)));
41002 DUK_FREE(heap, DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, g));
41003 }
41004}
41005
41006DUK_INTERNAL void duk_free_hstring_inner(duk_heap *heap, duk_hstring *h) {
41007 DUK_ASSERT(heap != NULL);
41008 DUK_ASSERT(h != NULL);
41009
41010 DUK_UNREF(heap);
41011 DUK_UNREF(h);
41012
41013#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_FREE)
41014 if (DUK_HSTRING_HAS_EXTDATA(h)) {
41015 DUK_DDD(DUK_DDDPRINT("free extstr: hstring %!O, extdata: %p",
41016 h, DUK_HSTRING_GET_EXTDATA((duk_hstring_external *) h)));
41017 DUK_USE_EXTSTR_FREE(heap->heap_udata, (const void *) DUK_HSTRING_GET_EXTDATA((duk_hstring_external *) h));
41018 }
41019#endif
41020}
41021
41022DUK_INTERNAL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr) {
41023 DUK_ASSERT(heap);
41024 DUK_ASSERT(hdr);
41025
41026 DUK_DDD(DUK_DDDPRINT("free heaphdr %p, htype %ld", (void *) hdr, (long) DUK_HEAPHDR_GET_TYPE(hdr)));
41027
41028 switch ((int) DUK_HEAPHDR_GET_TYPE(hdr)) {
41029 case DUK_HTYPE_STRING:
41030 duk_free_hstring_inner(heap, (duk_hstring *) hdr);
41031 break;
41032 case DUK_HTYPE_OBJECT:
41033 duk_free_hobject_inner(heap, (duk_hobject *) hdr);
41034 break;
41035 case DUK_HTYPE_BUFFER:
41036 duk_free_hbuffer_inner(heap, (duk_hbuffer *) hdr);
41037 break;
41038 default:
41039 DUK_UNREACHABLE();
41040 }
41041
41042 DUK_FREE(heap, hdr);
41043}
41044
41045/*
41046 * Free the heap.
41047 *
41048 * Frees heap-related non-heap-tracked allocations such as the
41049 * string intern table; then frees the heap allocated objects;
41050 * and finally frees the heap structure itself. Reference counts
41051 * and GC markers are ignored (and not updated) in this process,
41052 * and finalizers won't be called.
41053 *
41054 * The heap pointer and heap object pointers must not be used
41055 * after this call.
41056 */
41057
41058DUK_LOCAL void duk__free_allocated(duk_heap *heap) {
41059 duk_heaphdr *curr;
41060 duk_heaphdr *next;
41061
41062 curr = heap->heap_allocated;
41063 while (curr) {
41064 /* We don't log or warn about freeing zero refcount objects
41065 * because they may happen with finalizer processing.
41066 */
41067
41068 DUK_DDD(DUK_DDDPRINT("FINALFREE (allocated): %!iO",
41069 (duk_heaphdr *) curr));
41070 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
41071 duk_heap_free_heaphdr_raw(heap, curr);
41072 curr = next;
41073 }
41074}
41075
11fdf7f2 41076#if defined(DUK_USE_REFERENCE_COUNTING)
7c673cae
FG
41077DUK_LOCAL void duk__free_refzero_list(duk_heap *heap) {
41078 duk_heaphdr *curr;
41079 duk_heaphdr *next;
41080
41081 curr = heap->refzero_list;
41082 while (curr) {
41083 DUK_DDD(DUK_DDDPRINT("FINALFREE (refzero_list): %!iO",
41084 (duk_heaphdr *) curr));
41085 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
41086 duk_heap_free_heaphdr_raw(heap, curr);
41087 curr = next;
41088 }
41089}
41090#endif
41091
11fdf7f2 41092#if defined(DUK_USE_MARK_AND_SWEEP)
7c673cae
FG
41093DUK_LOCAL void duk__free_markandsweep_finalize_list(duk_heap *heap) {
41094 duk_heaphdr *curr;
41095 duk_heaphdr *next;
41096
41097 curr = heap->finalize_list;
41098 while (curr) {
41099 DUK_DDD(DUK_DDDPRINT("FINALFREE (finalize_list): %!iO",
41100 (duk_heaphdr *) curr));
41101 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
41102 duk_heap_free_heaphdr_raw(heap, curr);
41103 curr = next;
41104 }
41105}
41106#endif
41107
41108DUK_LOCAL void duk__free_stringtable(duk_heap *heap) {
41109 /* strings are only tracked by stringtable */
41110 duk_heap_free_strtab(heap);
41111}
41112
41113DUK_LOCAL void duk__free_run_finalizers(duk_heap *heap) {
41114 duk_hthread *thr;
41115 duk_heaphdr *curr;
11fdf7f2
TL
41116 duk_uint_t round_no;
41117 duk_size_t count_all;
41118 duk_size_t count_finalized;
41119 duk_size_t curr_limit;
7c673cae
FG
41120
41121 DUK_ASSERT(heap != NULL);
41122 DUK_ASSERT(heap->heap_thread != NULL);
11fdf7f2
TL
41123
41124#if defined(DUK_USE_REFERENCE_COUNTING)
7c673cae
FG
41125 DUK_ASSERT(heap->refzero_list == NULL); /* refzero not running -> must be empty */
41126#endif
11fdf7f2 41127#if defined(DUK_USE_MARK_AND_SWEEP)
7c673cae
FG
41128 DUK_ASSERT(heap->finalize_list == NULL); /* mark-and-sweep not running -> must be empty */
41129#endif
41130
41131 /* XXX: here again finalizer thread is the heap_thread which needs
41132 * to be coordinated with finalizer thread fixes.
41133 */
41134 thr = heap->heap_thread;
41135 DUK_ASSERT(thr != NULL);
41136
11fdf7f2
TL
41137 /* Prevent mark-and-sweep for the pending finalizers, also prevents
41138 * refzero handling from moving objects away from the heap_allocated
41139 * list. (The flag meaning is slightly abused here.)
41140 */
41141 DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap));
41142 DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap);
7c673cae 41143
11fdf7f2
TL
41144 curr_limit = 0; /* suppress warning, not used */
41145 for (round_no = 0; ; round_no++) {
41146 curr = heap->heap_allocated;
41147 count_all = 0;
41148 count_finalized = 0;
41149 while (curr) {
41150 count_all++;
41151 if (DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT) {
41152 /* Only objects in heap_allocated may have finalizers. Check that
41153 * the object itself has a _Finalizer property (own or inherited)
41154 * so that we don't execute finalizers for e.g. Proxy objects.
41155 */
41156 DUK_ASSERT(thr != NULL);
41157 DUK_ASSERT(curr != NULL);
41158
41159 if (duk_hobject_hasprop_raw(thr, (duk_hobject *) curr, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) {
41160 if (!DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) curr)) {
41161 DUK_ASSERT(DUK_HEAP_HAS_FINALIZER_NORESCUE(heap)); /* maps to finalizer 2nd argument */
41162 duk_hobject_run_finalizer(thr, (duk_hobject *) curr);
41163 count_finalized++;
41164 }
41165 }
7c673cae 41166 }
11fdf7f2
TL
41167 curr = DUK_HEAPHDR_GET_NEXT(heap, curr);
41168 }
41169
41170 /* Each round of finalizer execution may spawn new finalizable objects
41171 * which is normal behavior for some applications. Allow multiple
41172 * rounds of finalization, but use a shrinking limit based on the
41173 * first round to detect the case where a runaway finalizer creates
41174 * an unbounded amount of new finalizable objects. Finalizer rescue
41175 * is not supported: the semantics are unclear because most of the
41176 * objects being finalized here are already reachable. The finalizer
41177 * is given a boolean to indicate that rescue is not possible.
41178 *
41179 * See discussion in: https://github.com/svaarala/duktape/pull/473
41180 */
41181
41182 if (round_no == 0) {
41183 /* Cannot wrap: each object is at least 8 bytes so count is
41184 * at most 1/8 of that.
41185 */
41186 curr_limit = count_all * 2;
41187 } else {
41188 curr_limit = (curr_limit * 3) / 4; /* Decrease by 25% every round */
41189 }
41190 DUK_D(DUK_DPRINT("finalizer round %ld complete, %ld objects, tried to execute %ld finalizers, current limit is %ld",
41191 (long) round_no, (long) count_all, (long) count_finalized, (long) curr_limit));
41192
41193 if (count_finalized == 0) {
41194 DUK_D(DUK_DPRINT("no more finalizable objects, forced finalization finished"));
41195 break;
41196 }
41197 if (count_finalized >= curr_limit) {
41198 DUK_D(DUK_DPRINT("finalizer count above limit, potentially runaway finalizer; skip remaining finalizers"));
41199 break;
7c673cae 41200 }
7c673cae
FG
41201 }
41202
11fdf7f2
TL
41203 DUK_ASSERT(DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap));
41204 DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap);
7c673cae
FG
41205}
41206
41207DUK_INTERNAL void duk_heap_free(duk_heap *heap) {
41208 DUK_D(DUK_DPRINT("free heap: %p", (void *) heap));
41209
41210#if defined(DUK_USE_DEBUG)
41211 duk_heap_dump_strtab(heap);
41212#endif
41213
41214#if defined(DUK_USE_DEBUGGER_SUPPORT)
41215 /* Detach a debugger if attached (can be called multiple times)
41216 * safely.
41217 */
11fdf7f2
TL
41218 /* XXX: Add a flag to reject an attempt to re-attach? Otherwise
41219 * the detached callback may immediately reattach.
41220 */
7c673cae
FG
41221 duk_debug_do_detach(heap);
41222#endif
41223
41224 /* Execute finalizers before freeing the heap, even for reachable
41225 * objects, and regardless of whether or not mark-and-sweep is
41226 * enabled. This gives finalizers the chance to free any native
41227 * resources like file handles, allocations made outside Duktape,
11fdf7f2
TL
41228 * etc. This is quite tricky to get right, so that all finalizer
41229 * guarantees are honored.
7c673cae
FG
41230 *
41231 * XXX: this perhaps requires an execution time limit.
41232 */
41233 DUK_D(DUK_DPRINT("execute finalizers before freeing heap"));
11fdf7f2
TL
41234#if defined(DUK_USE_MARK_AND_SWEEP)
41235 /* Run mark-and-sweep a few times just in case (unreachable object
41236 * finalizers run already here). The last round must rescue objects
41237 * from the previous round without running any more finalizers. This
41238 * ensures rescued objects get their FINALIZED flag cleared so that
41239 * their finalizer is called once more in forced finalization to
41240 * satisfy finalizer guarantees. However, we don't want to run any
41241 * more finalizer because that'd required one more loop, and so on.
41242 */
41243 DUK_D(DUK_DPRINT("forced gc #1 in heap destruction"));
7c673cae 41244 duk_heap_mark_and_sweep(heap, 0);
11fdf7f2 41245 DUK_D(DUK_DPRINT("forced gc #2 in heap destruction"));
7c673cae 41246 duk_heap_mark_and_sweep(heap, 0);
11fdf7f2
TL
41247 DUK_D(DUK_DPRINT("forced gc #3 in heap destruction (don't run finalizers)"));
41248 duk_heap_mark_and_sweep(heap, DUK_MS_FLAG_SKIP_FINALIZERS); /* skip finalizers; queue finalizable objects to heap_allocated */
7c673cae 41249#endif
11fdf7f2
TL
41250
41251 DUK_HEAP_SET_FINALIZER_NORESCUE(heap); /* rescue no longer supported */
7c673cae
FG
41252 duk__free_run_finalizers(heap);
41253
41254 /* Note: heap->heap_thread, heap->curr_thread, and heap->heap_object
41255 * are on the heap allocated list.
41256 */
41257
41258 DUK_D(DUK_DPRINT("freeing heap objects of heap: %p", (void *) heap));
41259 duk__free_allocated(heap);
41260
11fdf7f2 41261#if defined(DUK_USE_REFERENCE_COUNTING)
7c673cae
FG
41262 DUK_D(DUK_DPRINT("freeing refzero list of heap: %p", (void *) heap));
41263 duk__free_refzero_list(heap);
41264#endif
41265
11fdf7f2 41266#if defined(DUK_USE_MARK_AND_SWEEP)
7c673cae
FG
41267 DUK_D(DUK_DPRINT("freeing mark-and-sweep finalize list of heap: %p", (void *) heap));
41268 duk__free_markandsweep_finalize_list(heap);
41269#endif
41270
41271 DUK_D(DUK_DPRINT("freeing string table of heap: %p", (void *) heap));
41272 duk__free_stringtable(heap);
41273
41274 DUK_D(DUK_DPRINT("freeing heap structure: %p", (void *) heap));
41275 heap->free_func(heap->heap_udata, heap);
41276}
41277
41278/*
41279 * Allocate a heap.
41280 *
11fdf7f2
TL
41281 * String table is initialized with built-in strings from genbuiltins.py,
41282 * either by dynamically creating the strings or by referring to ROM strings.
7c673cae
FG
41283 */
41284
11fdf7f2
TL
41285#if defined(DUK_USE_ROM_STRINGS)
41286DUK_LOCAL duk_bool_t duk__init_heap_strings(duk_heap *heap) {
41287#if defined(DUK_USE_ASSERTIONS)
41288 duk_small_uint_t i;
41289#endif
41290
41291 /* With ROM-based strings, heap->strs[] and thr->strs[] are omitted
41292 * so nothing to initialize for strs[].
41293 */
41294
41295#if defined(DUK_USE_ASSERTIONS)
41296 for (i = 0; i < sizeof(duk_rom_strings) / sizeof(const duk_hstring *); i++) {
41297 duk_uint32_t hash;
41298 const duk_hstring *h;
41299 h = duk_rom_strings[i];
41300 DUK_ASSERT(h != NULL);
41301 hash = duk_heap_hashstring(heap, (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
41302 DUK_DD(DUK_DDPRINT("duk_rom_strings[%d] -> hash 0x%08lx, computed 0x%08lx",
41303 (int) i, (unsigned long) DUK_HSTRING_GET_HASH(h), (unsigned long) hash));
41304 DUK_ASSERT(hash == (duk_uint32_t) DUK_HSTRING_GET_HASH(h));
41305 }
41306#endif
41307 return 1;
41308}
41309#else /* DUK_USE_ROM_STRINGS */
7c673cae
FG
41310DUK_LOCAL duk_bool_t duk__init_heap_strings(duk_heap *heap) {
41311 duk_bitdecoder_ctx bd_ctx;
41312 duk_bitdecoder_ctx *bd = &bd_ctx; /* convenience */
41313 duk_small_uint_t i, j;
41314
41315 DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
41316 bd->data = (const duk_uint8_t *) duk_strings_data;
41317 bd->length = (duk_size_t) DUK_STRDATA_DATA_LENGTH;
41318
41319 for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
41320 duk_uint8_t tmp[DUK_STRDATA_MAX_STRLEN];
41321 duk_hstring *h;
41322 duk_small_uint_t len;
41323 duk_small_uint_t mode;
41324 duk_small_uint_t t;
41325
41326 len = duk_bd_decode(bd, 5);
41327 mode = 32; /* 0 = uppercase, 32 = lowercase (= 'a' - 'A') */
41328 for (j = 0; j < len; j++) {
41329 t = duk_bd_decode(bd, 5);
41330 if (t < DUK__BITPACK_LETTER_LIMIT) {
41331 t = t + DUK_ASC_UC_A + mode;
41332 } else if (t == DUK__BITPACK_UNDERSCORE) {
41333 t = DUK_ASC_UNDERSCORE;
41334 } else if (t == DUK__BITPACK_FF) {
41335 /* Internal keys are prefixed with 0xFF in the stringtable
41336 * (which makes them invalid UTF-8 on purpose).
41337 */
41338 t = 0xff;
41339 } else if (t == DUK__BITPACK_SWITCH1) {
41340 t = duk_bd_decode(bd, 5);
41341 DUK_ASSERT_DISABLE(t >= 0); /* unsigned */
41342 DUK_ASSERT(t <= 25);
41343 t = t + DUK_ASC_UC_A + (mode ^ 32);
41344 } else if (t == DUK__BITPACK_SWITCH) {
41345 mode = mode ^ 32;
41346 t = duk_bd_decode(bd, 5);
41347 DUK_ASSERT_DISABLE(t >= 0);
41348 DUK_ASSERT(t <= 25);
41349 t = t + DUK_ASC_UC_A + mode;
41350 } else if (t == DUK__BITPACK_SEVENBIT) {
41351 t = duk_bd_decode(bd, 7);
41352 }
41353 tmp[j] = (duk_uint8_t) t;
41354 }
41355
41356 /* No need to length check string: it will never exceed even
41357 * the 16-bit length maximum.
41358 */
41359 DUK_ASSERT(len <= 0xffffUL);
41360 DUK_DDD(DUK_DDDPRINT("intern built-in string %ld", (long) i));
41361 h = duk_heap_string_intern(heap, tmp, len);
41362 if (!h) {
41363 goto error;
41364 }
11fdf7f2 41365 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h));
7c673cae
FG
41366
41367 /* Special flags checks. Since these strings are always
41368 * reachable and a string cannot appear twice in the string
41369 * table, there's no need to check/set these flags elsewhere.
41370 * The 'internal' flag is set by string intern code.
41371 */
41372 if (i == DUK_STRIDX_EVAL || i == DUK_STRIDX_LC_ARGUMENTS) {
41373 DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(h);
41374 }
41375 if (i >= DUK_STRIDX_START_RESERVED && i < DUK_STRIDX_END_RESERVED) {
41376 DUK_HSTRING_SET_RESERVED_WORD(h);
41377 if (i >= DUK_STRIDX_START_STRICT_RESERVED) {
41378 DUK_HSTRING_SET_STRICT_RESERVED_WORD(h);
41379 }
41380 }
41381
41382 DUK_DDD(DUK_DDDPRINT("interned: %!O", (duk_heaphdr *) h));
41383
41384 /* XXX: The incref macro takes a thread pointer but doesn't
41385 * use it right now.
41386 */
41387 DUK_HSTRING_INCREF(_never_referenced_, h);
41388
41389#if defined(DUK_USE_HEAPPTR16)
41390 heap->strs16[i] = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
41391#else
41392 heap->strs[i] = h;
41393#endif
41394 }
41395
41396 return 1;
41397
41398 error:
41399 return 0;
41400}
11fdf7f2 41401#endif /* DUK_USE_ROM_STRINGS */
7c673cae
FG
41402
41403DUK_LOCAL duk_bool_t duk__init_heap_thread(duk_heap *heap) {
41404 duk_hthread *thr;
41405
41406 DUK_DD(DUK_DDPRINT("heap init: alloc heap thread"));
41407 thr = duk_hthread_alloc(heap,
41408 DUK_HOBJECT_FLAG_EXTENSIBLE |
41409 DUK_HOBJECT_FLAG_THREAD |
41410 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD));
41411 if (!thr) {
41412 DUK_D(DUK_DPRINT("failed to alloc heap_thread"));
41413 return 0;
41414 }
41415 thr->state = DUK_HTHREAD_STATE_INACTIVE;
11fdf7f2
TL
41416#if defined(DUK_USE_ROM_STRINGS)
41417 /* No strs[] pointer. */
41418#else /* DUK_USE_ROM_STRINGS */
7c673cae
FG
41419#if defined(DUK_USE_HEAPPTR16)
41420 thr->strs16 = heap->strs16;
41421#else
41422 thr->strs = heap->strs;
41423#endif
11fdf7f2 41424#endif /* DUK_USE_ROM_STRINGS */
7c673cae
FG
41425
41426 heap->heap_thread = thr;
41427 DUK_HTHREAD_INCREF(thr, thr); /* Note: first argument not really used */
41428
41429 /* 'thr' is now reachable */
41430
41431 if (!duk_hthread_init_stacks(heap, thr)) {
41432 return 0;
41433 }
41434
41435 /* XXX: this may now fail, and is not handled correctly */
41436 duk_hthread_create_builtin_objects(thr);
41437
41438 /* default prototype (Note: 'thr' must be reachable) */
41439 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) thr, thr->builtins[DUK_BIDX_THREAD_PROTOTYPE]);
41440
41441 return 1;
41442}
41443
11fdf7f2 41444#if defined(DUK_USE_DEBUG)
7c673cae
FG
41445#define DUK__DUMPSZ(t) do { \
41446 DUK_D(DUK_DPRINT("" #t "=%ld", (long) sizeof(t))); \
41447 } while (0)
41448
41449/* These is not 100% because format would need to be non-portable "long long".
41450 * Also print out as doubles to catch cases where the "long" type is not wide
41451 * enough; the limits will then not be printed accurately but the magnitude
41452 * will be correct.
41453 */
41454#define DUK__DUMPLM_SIGNED_RAW(t,a,b) do { \
41455 DUK_D(DUK_DPRINT(t "=[%ld,%ld]=[%lf,%lf]", \
41456 (long) (a), (long) (b), \
41457 (double) (a), (double) (b))); \
11fdf7f2 41458 } while (0)
7c673cae
FG
41459#define DUK__DUMPLM_UNSIGNED_RAW(t,a,b) do { \
41460 DUK_D(DUK_DPRINT(t "=[%lu,%lu]=[%lf,%lf]", \
41461 (unsigned long) (a), (unsigned long) (b), \
41462 (double) (a), (double) (b))); \
11fdf7f2 41463 } while (0)
7c673cae
FG
41464#define DUK__DUMPLM_SIGNED(t) do { \
41465 DUK__DUMPLM_SIGNED_RAW("DUK_" #t "_{MIN,MAX}", DUK_##t##_MIN, DUK_##t##_MAX); \
11fdf7f2 41466 } while (0)
7c673cae
FG
41467#define DUK__DUMPLM_UNSIGNED(t) do { \
41468 DUK__DUMPLM_UNSIGNED_RAW("DUK_" #t "_{MIN,MAX}", DUK_##t##_MIN, DUK_##t##_MAX); \
11fdf7f2 41469 } while (0)
7c673cae
FG
41470
41471DUK_LOCAL void duk__dump_type_sizes(void) {
41472 DUK_D(DUK_DPRINT("sizeof()"));
41473
41474 /* basic platform types */
41475 DUK__DUMPSZ(char);
41476 DUK__DUMPSZ(short);
41477 DUK__DUMPSZ(int);
41478 DUK__DUMPSZ(long);
41479 DUK__DUMPSZ(double);
41480 DUK__DUMPSZ(void *);
41481 DUK__DUMPSZ(size_t);
41482
41483 /* basic types from duk_features.h */
41484 DUK__DUMPSZ(duk_uint8_t);
41485 DUK__DUMPSZ(duk_int8_t);
41486 DUK__DUMPSZ(duk_uint16_t);
41487 DUK__DUMPSZ(duk_int16_t);
41488 DUK__DUMPSZ(duk_uint32_t);
41489 DUK__DUMPSZ(duk_int32_t);
41490 DUK__DUMPSZ(duk_uint64_t);
41491 DUK__DUMPSZ(duk_int64_t);
41492 DUK__DUMPSZ(duk_uint_least8_t);
41493 DUK__DUMPSZ(duk_int_least8_t);
41494 DUK__DUMPSZ(duk_uint_least16_t);
41495 DUK__DUMPSZ(duk_int_least16_t);
41496 DUK__DUMPSZ(duk_uint_least32_t);
41497 DUK__DUMPSZ(duk_int_least32_t);
41498#if defined(DUK_USE_64BIT_OPS)
41499 DUK__DUMPSZ(duk_uint_least64_t);
41500 DUK__DUMPSZ(duk_int_least64_t);
41501#endif
41502 DUK__DUMPSZ(duk_uint_fast8_t);
41503 DUK__DUMPSZ(duk_int_fast8_t);
41504 DUK__DUMPSZ(duk_uint_fast16_t);
41505 DUK__DUMPSZ(duk_int_fast16_t);
41506 DUK__DUMPSZ(duk_uint_fast32_t);
41507 DUK__DUMPSZ(duk_int_fast32_t);
41508#if defined(DUK_USE_64BIT_OPS)
41509 DUK__DUMPSZ(duk_uint_fast64_t);
41510 DUK__DUMPSZ(duk_int_fast64_t);
41511#endif
41512 DUK__DUMPSZ(duk_uintptr_t);
41513 DUK__DUMPSZ(duk_intptr_t);
41514 DUK__DUMPSZ(duk_uintmax_t);
41515 DUK__DUMPSZ(duk_intmax_t);
41516 DUK__DUMPSZ(duk_double_t);
41517
41518 /* important chosen base types */
41519 DUK__DUMPSZ(duk_int_t);
41520 DUK__DUMPSZ(duk_uint_t);
41521 DUK__DUMPSZ(duk_int_fast_t);
41522 DUK__DUMPSZ(duk_uint_fast_t);
41523 DUK__DUMPSZ(duk_small_int_t);
41524 DUK__DUMPSZ(duk_small_uint_t);
41525 DUK__DUMPSZ(duk_small_int_fast_t);
41526 DUK__DUMPSZ(duk_small_uint_fast_t);
41527
41528 /* some derived types */
41529 DUK__DUMPSZ(duk_codepoint_t);
41530 DUK__DUMPSZ(duk_ucodepoint_t);
41531 DUK__DUMPSZ(duk_idx_t);
41532 DUK__DUMPSZ(duk_errcode_t);
41533 DUK__DUMPSZ(duk_uarridx_t);
41534
41535 /* tval */
41536 DUK__DUMPSZ(duk_double_union);
41537 DUK__DUMPSZ(duk_tval);
41538
41539 /* structs from duk_forwdecl.h */
11fdf7f2 41540 DUK__DUMPSZ(duk_jmpbuf); /* just one 'int' for C++ exceptions */
7c673cae
FG
41541 DUK__DUMPSZ(duk_heaphdr);
41542 DUK__DUMPSZ(duk_heaphdr_string);
41543 DUK__DUMPSZ(duk_hstring);
41544 DUK__DUMPSZ(duk_hstring_external);
41545 DUK__DUMPSZ(duk_hobject);
41546 DUK__DUMPSZ(duk_hcompiledfunction);
41547 DUK__DUMPSZ(duk_hnativefunction);
41548 DUK__DUMPSZ(duk_hthread);
41549 DUK__DUMPSZ(duk_hbuffer);
41550 DUK__DUMPSZ(duk_hbuffer_fixed);
41551 DUK__DUMPSZ(duk_hbuffer_dynamic);
41552 DUK__DUMPSZ(duk_hbuffer_external);
41553 DUK__DUMPSZ(duk_propaccessor);
41554 DUK__DUMPSZ(duk_propvalue);
41555 DUK__DUMPSZ(duk_propdesc);
41556 DUK__DUMPSZ(duk_heap);
41557#if defined(DUK_USE_STRTAB_CHAIN)
41558 DUK__DUMPSZ(duk_strtab_entry);
41559#endif
41560 DUK__DUMPSZ(duk_activation);
41561 DUK__DUMPSZ(duk_catcher);
41562 DUK__DUMPSZ(duk_strcache);
41563 DUK__DUMPSZ(duk_ljstate);
41564 DUK__DUMPSZ(duk_fixedbuffer);
41565 DUK__DUMPSZ(duk_bitdecoder_ctx);
41566 DUK__DUMPSZ(duk_bitencoder_ctx);
41567 DUK__DUMPSZ(duk_token);
41568 DUK__DUMPSZ(duk_re_token);
41569 DUK__DUMPSZ(duk_lexer_point);
41570 DUK__DUMPSZ(duk_lexer_ctx);
41571 DUK__DUMPSZ(duk_compiler_instr);
41572 DUK__DUMPSZ(duk_compiler_func);
41573 DUK__DUMPSZ(duk_compiler_ctx);
41574 DUK__DUMPSZ(duk_re_matcher_ctx);
41575 DUK__DUMPSZ(duk_re_compiler_ctx);
41576}
41577DUK_LOCAL void duk__dump_type_limits(void) {
41578 DUK_D(DUK_DPRINT("limits"));
41579
41580 /* basic types */
41581 DUK__DUMPLM_SIGNED(INT8);
41582 DUK__DUMPLM_UNSIGNED(UINT8);
41583 DUK__DUMPLM_SIGNED(INT_FAST8);
41584 DUK__DUMPLM_UNSIGNED(UINT_FAST8);
41585 DUK__DUMPLM_SIGNED(INT_LEAST8);
41586 DUK__DUMPLM_UNSIGNED(UINT_LEAST8);
41587 DUK__DUMPLM_SIGNED(INT16);
41588 DUK__DUMPLM_UNSIGNED(UINT16);
41589 DUK__DUMPLM_SIGNED(INT_FAST16);
41590 DUK__DUMPLM_UNSIGNED(UINT_FAST16);
41591 DUK__DUMPLM_SIGNED(INT_LEAST16);
41592 DUK__DUMPLM_UNSIGNED(UINT_LEAST16);
41593 DUK__DUMPLM_SIGNED(INT32);
41594 DUK__DUMPLM_UNSIGNED(UINT32);
41595 DUK__DUMPLM_SIGNED(INT_FAST32);
41596 DUK__DUMPLM_UNSIGNED(UINT_FAST32);
41597 DUK__DUMPLM_SIGNED(INT_LEAST32);
41598 DUK__DUMPLM_UNSIGNED(UINT_LEAST32);
41599#if defined(DUK_USE_64BIT_OPS)
41600 DUK__DUMPLM_SIGNED(INT64);
41601 DUK__DUMPLM_UNSIGNED(UINT64);
41602 DUK__DUMPLM_SIGNED(INT_FAST64);
41603 DUK__DUMPLM_UNSIGNED(UINT_FAST64);
41604 DUK__DUMPLM_SIGNED(INT_LEAST64);
41605 DUK__DUMPLM_UNSIGNED(UINT_LEAST64);
41606#endif
41607 DUK__DUMPLM_SIGNED(INTPTR);
41608 DUK__DUMPLM_UNSIGNED(UINTPTR);
41609 DUK__DUMPLM_SIGNED(INTMAX);
41610 DUK__DUMPLM_UNSIGNED(UINTMAX);
41611
41612 /* derived types */
41613 DUK__DUMPLM_SIGNED(INT);
41614 DUK__DUMPLM_UNSIGNED(UINT);
41615 DUK__DUMPLM_SIGNED(INT_FAST);
41616 DUK__DUMPLM_UNSIGNED(UINT_FAST);
41617 DUK__DUMPLM_SIGNED(SMALL_INT);
41618 DUK__DUMPLM_UNSIGNED(SMALL_UINT);
41619 DUK__DUMPLM_SIGNED(SMALL_INT_FAST);
41620 DUK__DUMPLM_UNSIGNED(SMALL_UINT_FAST);
41621}
41622#undef DUK__DUMPSZ
41623#undef DUK__DUMPLM_SIGNED_RAW
41624#undef DUK__DUMPLM_UNSIGNED_RAW
41625#undef DUK__DUMPLM_SIGNED
41626#undef DUK__DUMPLM_UNSIGNED
41627
41628DUK_LOCAL void duk__dump_misc_options(void) {
41629 DUK_D(DUK_DPRINT("DUK_VERSION: %ld", (long) DUK_VERSION));
41630 DUK_D(DUK_DPRINT("DUK_GIT_DESCRIBE: %s", DUK_GIT_DESCRIBE));
11fdf7f2
TL
41631 DUK_D(DUK_DPRINT("OS string: %s", DUK_USE_OS_STRING));
41632 DUK_D(DUK_DPRINT("architecture string: %s", DUK_USE_ARCH_STRING));
41633 DUK_D(DUK_DPRINT("compiler string: %s", DUK_USE_COMPILER_STRING));
7c673cae
FG
41634#if defined(DUK_USE_PACKED_TVAL)
41635 DUK_D(DUK_DPRINT("DUK_USE_PACKED_TVAL: yes"));
41636#else
41637 DUK_D(DUK_DPRINT("DUK_USE_PACKED_TVAL: no"));
41638#endif
11fdf7f2
TL
41639#if defined(DUK_USE_VARIADIC_MACROS)
41640 DUK_D(DUK_DPRINT("DUK_USE_VARIADIC_MACROS: yes"));
41641#else
41642 DUK_D(DUK_DPRINT("DUK_USE_VARIADIC_MACROS: no"));
41643#endif
7c673cae 41644#if defined(DUK_USE_INTEGER_LE)
11fdf7f2 41645 DUK_D(DUK_DPRINT("integer endianness: little"));
7c673cae 41646#elif defined(DUK_USE_INTEGER_ME)
11fdf7f2 41647 DUK_D(DUK_DPRINT("integer endianness: mixed"));
7c673cae 41648#elif defined(DUK_USE_INTEGER_BE)
11fdf7f2 41649 DUK_D(DUK_DPRINT("integer endianness: big"));
7c673cae 41650#else
11fdf7f2 41651 DUK_D(DUK_DPRINT("integer endianness: ???"));
7c673cae
FG
41652#endif
41653#if defined(DUK_USE_DOUBLE_LE)
41654 DUK_D(DUK_DPRINT("IEEE double endianness: little"));
41655#elif defined(DUK_USE_DOUBLE_ME)
41656 DUK_D(DUK_DPRINT("IEEE double endianness: mixed"));
41657#elif defined(DUK_USE_DOUBLE_BE)
41658 DUK_D(DUK_DPRINT("IEEE double endianness: big"));
41659#else
41660 DUK_D(DUK_DPRINT("IEEE double endianness: ???"));
41661#endif
41662}
41663#endif /* DUK_USE_DEBUG */
41664
41665DUK_INTERNAL
41666duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
41667 duk_realloc_function realloc_func,
41668 duk_free_function free_func,
41669 void *heap_udata,
41670 duk_fatal_function fatal_func) {
41671 duk_heap *res = NULL;
41672
41673 /* Silence a few global unused warnings here. */
41674 DUK_UNREF(duk_str_unsupported);
41675
41676 DUK_D(DUK_DPRINT("allocate heap"));
41677
41678 /*
41679 * Debug dump type sizes
41680 */
41681
11fdf7f2 41682#if defined(DUK_USE_DEBUG)
7c673cae
FG
41683 duk__dump_misc_options();
41684 duk__dump_type_sizes();
41685 duk__dump_type_limits();
41686#endif
41687
41688 /*
41689 * If selftests enabled, run them as early as possible
41690 */
11fdf7f2 41691#if defined(DUK_USE_SELF_TESTS)
7c673cae
FG
41692 DUK_D(DUK_DPRINT("running self tests"));
41693 duk_selftest_run_tests();
41694 DUK_D(DUK_DPRINT("self tests passed"));
41695#endif
41696
41697 /*
41698 * Computed values (e.g. INFINITY)
41699 */
41700
11fdf7f2 41701#if defined(DUK_USE_COMPUTED_NAN)
7c673cae
FG
41702 do {
41703 /* Workaround for some exotic platforms where NAN is missing
41704 * and the expression (0.0 / 0.0) does NOT result in a NaN.
41705 * Such platforms use the global 'duk_computed_nan' which must
41706 * be initialized at runtime. Use 'volatile' to ensure that
41707 * the compiler will actually do the computation and not try
41708 * to do constant folding which might result in the original
41709 * problem.
41710 */
41711 volatile double dbl1 = 0.0;
41712 volatile double dbl2 = 0.0;
41713 duk_computed_nan = dbl1 / dbl2;
41714 } while (0);
41715#endif
41716
11fdf7f2 41717#if defined(DUK_USE_COMPUTED_INFINITY)
7c673cae
FG
41718 do {
41719 /* Similar workaround for INFINITY. */
41720 volatile double dbl1 = 1.0;
41721 volatile double dbl2 = 0.0;
41722 duk_computed_infinity = dbl1 / dbl2;
41723 } while (0);
41724#endif
41725
41726 /*
41727 * Allocate heap struct
41728 *
41729 * Use a raw call, all macros expect the heap to be initialized
41730 */
41731
41732 res = (duk_heap *) alloc_func(heap_udata, sizeof(duk_heap));
41733 if (!res) {
41734 goto error;
41735 }
41736
41737 /*
41738 * Zero the struct, and start initializing roughly in order
41739 */
41740
41741 DUK_MEMZERO(res, sizeof(*res));
41742
41743 /* explicit NULL inits */
11fdf7f2 41744#if defined(DUK_USE_EXPLICIT_NULL_INIT)
7c673cae
FG
41745 res->heap_udata = NULL;
41746 res->heap_allocated = NULL;
11fdf7f2 41747#if defined(DUK_USE_REFERENCE_COUNTING)
7c673cae
FG
41748 res->refzero_list = NULL;
41749 res->refzero_list_tail = NULL;
41750#endif
11fdf7f2 41751#if defined(DUK_USE_MARK_AND_SWEEP)
7c673cae
FG
41752 res->finalize_list = NULL;
41753#endif
41754 res->heap_thread = NULL;
41755 res->curr_thread = NULL;
41756 res->heap_object = NULL;
41757#if defined(DUK_USE_STRTAB_CHAIN)
41758 /* nothing to NULL */
41759#elif defined(DUK_USE_STRTAB_PROBE)
41760#if defined(DUK_USE_HEAPPTR16)
41761 res->strtable16 = (duk_uint16_t *) NULL;
41762#else
41763 res->strtable = (duk_hstring **) NULL;
41764#endif
41765#endif
11fdf7f2
TL
41766#if defined(DUK_USE_ROM_STRINGS)
41767 /* no res->strs[] */
41768#else /* DUK_USE_ROM_STRINGS */
7c673cae 41769#if defined(DUK_USE_HEAPPTR16)
11fdf7f2 41770 /* res->strs16[] is zeroed and zero decodes to NULL, so no NULL inits. */
7c673cae
FG
41771#else
41772 {
41773 duk_small_uint_t i;
41774 for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
41775 res->strs[i] = NULL;
41776 }
41777 }
41778#endif
11fdf7f2 41779#endif /* DUK_USE_ROM_STRINGS */
7c673cae
FG
41780#if defined(DUK_USE_DEBUGGER_SUPPORT)
41781 res->dbg_read_cb = NULL;
41782 res->dbg_write_cb = NULL;
41783 res->dbg_peek_cb = NULL;
41784 res->dbg_read_flush_cb = NULL;
41785 res->dbg_write_flush_cb = NULL;
11fdf7f2 41786 res->dbg_request_cb = NULL;
7c673cae
FG
41787 res->dbg_udata = NULL;
41788 res->dbg_step_thread = NULL;
41789#endif
41790#endif /* DUK_USE_EXPLICIT_NULL_INIT */
41791
41792 res->alloc_func = alloc_func;
41793 res->realloc_func = realloc_func;
41794 res->free_func = free_func;
41795 res->heap_udata = heap_udata;
41796 res->fatal_func = fatal_func;
41797
41798#if defined(DUK_USE_HEAPPTR16)
41799 /* XXX: zero assumption */
41800 res->heapptr_null16 = DUK_USE_HEAPPTR_ENC16(res->heap_udata, (void *) NULL);
41801 res->heapptr_deleted16 = DUK_USE_HEAPPTR_ENC16(res->heap_udata, (void *) DUK_STRTAB_DELETED_MARKER(res));
41802#endif
41803
41804 /* res->mark_and_sweep_trigger_counter == 0 -> now causes immediate GC; which is OK */
41805
41806 res->call_recursion_depth = 0;
41807 res->call_recursion_limit = DUK_USE_NATIVE_CALL_RECLIMIT;
41808
41809 /* XXX: use the pointer as a seed for now: mix in time at least */
41810
41811 /* The casts through duk_intr_pt is to avoid the following GCC warning:
41812 *
41813 * warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
41814 *
41815 * This still generates a /Wp64 warning on VS2010 when compiling for x86.
41816 */
11fdf7f2
TL
41817#if defined(DUK_USE_ROM_STRINGS)
41818 /* XXX: make a common DUK_USE_ option, and allow custom fixed seed? */
41819 DUK_D(DUK_DPRINT("using rom strings, force heap hash_seed to fixed value 0x%08lx", (long) DUK__FIXED_HASH_SEED));
41820 res->hash_seed = (duk_uint32_t) DUK__FIXED_HASH_SEED;
41821#else /* DUK_USE_ROM_STRINGS */
7c673cae 41822 res->hash_seed = (duk_uint32_t) (duk_intptr_t) res;
11fdf7f2
TL
41823#if !defined(DUK_USE_STRHASH_DENSE)
41824 res->hash_seed ^= 5381; /* Bernstein hash init value is normally 5381; XOR it in in case pointer low bits are 0 */
41825#endif
41826#endif /* DUK_USE_ROM_STRINGS */
7c673cae
FG
41827 res->rnd_state = (duk_uint32_t) (duk_intptr_t) res;
41828
11fdf7f2 41829#if defined(DUK_USE_EXPLICIT_NULL_INIT)
7c673cae
FG
41830 res->lj.jmpbuf_ptr = NULL;
41831#endif
41832 DUK_ASSERT(res->lj.type == DUK_LJ_TYPE_UNKNOWN); /* zero */
41833
11fdf7f2
TL
41834 DUK_TVAL_SET_UNDEFINED(&res->lj.value1);
41835 DUK_TVAL_SET_UNDEFINED(&res->lj.value2);
7c673cae
FG
41836
41837#if (DUK_STRTAB_INITIAL_SIZE < DUK_UTIL_MIN_HASH_PRIME)
41838#error initial heap stringtable size is defined incorrectly
41839#endif
41840
41841 /*
41842 * Init stringtable: fixed variant
41843 */
41844
41845#if defined(DUK_USE_STRTAB_CHAIN)
41846 DUK_MEMZERO(res->strtable, sizeof(duk_strtab_entry) * DUK_STRTAB_CHAIN_SIZE);
11fdf7f2 41847#if defined(DUK_USE_EXPLICIT_NULL_INIT)
7c673cae
FG
41848 {
41849 duk_small_uint_t i;
41850 for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
41851#if defined(DUK_USE_HEAPPTR16)
41852 res->strtable[i].u.str16 = res->heapptr_null16;
41853#else
41854 res->strtable[i].u.str = NULL;
41855#endif
41856 }
41857 }
41858#endif /* DUK_USE_EXPLICIT_NULL_INIT */
41859#endif /* DUK_USE_STRTAB_CHAIN */
41860
41861 /*
41862 * Init stringtable: probe variant
41863 */
41864
41865#if defined(DUK_USE_STRTAB_PROBE)
41866#if defined(DUK_USE_HEAPPTR16)
41867 res->strtable16 = (duk_uint16_t *) alloc_func(heap_udata, sizeof(duk_uint16_t) * DUK_STRTAB_INITIAL_SIZE);
41868 if (!res->strtable16) {
41869 goto error;
41870 }
41871#else /* DUK_USE_HEAPPTR16 */
41872 res->strtable = (duk_hstring **) alloc_func(heap_udata, sizeof(duk_hstring *) * DUK_STRTAB_INITIAL_SIZE);
41873 if (!res->strtable) {
41874 goto error;
41875 }
41876#endif /* DUK_USE_HEAPPTR16 */
41877 res->st_size = DUK_STRTAB_INITIAL_SIZE;
11fdf7f2 41878#if defined(DUK_USE_EXPLICIT_NULL_INIT)
7c673cae
FG
41879 {
41880 duk_small_uint_t i;
41881 DUK_ASSERT(res->st_size == DUK_STRTAB_INITIAL_SIZE);
41882 for (i = 0; i < DUK_STRTAB_INITIAL_SIZE; i++) {
41883#if defined(DUK_USE_HEAPPTR16)
41884 res->strtable16[i] = res->heapptr_null16;
41885#else
41886 res->strtable[i] = NULL;
41887#endif
41888 }
41889 }
41890#else /* DUK_USE_EXPLICIT_NULL_INIT */
41891#if defined(DUK_USE_HEAPPTR16)
41892 DUK_MEMZERO(res->strtable16, sizeof(duk_uint16_t) * DUK_STRTAB_INITIAL_SIZE);
41893#else
41894 DUK_MEMZERO(res->strtable, sizeof(duk_hstring *) * DUK_STRTAB_INITIAL_SIZE);
41895#endif
41896#endif /* DUK_USE_EXPLICIT_NULL_INIT */
41897#endif /* DUK_USE_STRTAB_PROBE */
41898
41899 /*
41900 * Init stringcache
41901 */
41902
11fdf7f2 41903#if defined(DUK_USE_EXPLICIT_NULL_INIT)
7c673cae
FG
41904 {
41905 duk_small_uint_t i;
41906 for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
41907 res->strcache[i].h = NULL;
41908 }
41909 }
41910#endif
41911
41912 /* XXX: error handling is incomplete. It would be cleanest if
41913 * there was a setjmp catchpoint, so that all init code could
41914 * freely throw errors. If that were the case, the return code
41915 * passing here could be removed.
41916 */
41917
41918 /*
41919 * Init built-in strings
41920 */
41921
41922 DUK_DD(DUK_DDPRINT("HEAP: INIT STRINGS"));
41923 if (!duk__init_heap_strings(res)) {
41924 goto error;
41925 }
41926
41927 /*
41928 * Init the heap thread
41929 */
41930
41931 DUK_DD(DUK_DDPRINT("HEAP: INIT HEAP THREAD"));
41932 if (!duk__init_heap_thread(res)) {
41933 goto error;
41934 }
41935
11fdf7f2
TL
41936 DUK_ASSERT(res->heap_thread != NULL);
41937 res->rnd_state ^= (duk_uint32_t) DUK_USE_DATE_GET_NOW((duk_context *) res->heap_thread);
41938
7c673cae
FG
41939 /*
41940 * Init the heap object
41941 */
41942
41943 DUK_DD(DUK_DDPRINT("HEAP: INIT HEAP OBJECT"));
41944 DUK_ASSERT(res->heap_thread != NULL);
41945 res->heap_object = duk_hobject_alloc(res, DUK_HOBJECT_FLAG_EXTENSIBLE |
41946 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT));
41947 if (!res->heap_object) {
41948 goto error;
41949 }
41950 DUK_HOBJECT_INCREF(res->heap_thread, res->heap_object);
41951
41952 /*
41953 * All done
41954 */
41955
41956 DUK_D(DUK_DPRINT("allocated heap: %p", (void *) res));
41957 return res;
41958
41959 error:
41960 DUK_D(DUK_DPRINT("heap allocation failed"));
41961
41962 if (res) {
41963 /* assumes that allocated pointers and alloc funcs are valid
41964 * if res exists
41965 */
41966 DUK_ASSERT(res->alloc_func != NULL);
41967 DUK_ASSERT(res->realloc_func != NULL);
41968 DUK_ASSERT(res->free_func != NULL);
41969 duk_heap_free(res);
41970 }
41971 return NULL;
41972}
11fdf7f2
TL
41973
41974#undef DUK__BITPACK_LETTER_LIMIT
41975#undef DUK__BITPACK_UNDERSCORE
41976#undef DUK__BITPACK_FF
41977#undef DUK__BITPACK_SWITCH1
41978#undef DUK__BITPACK_SWITCH
41979#undef DUK__BITPACK_SEVENBIT
41980#undef DUK__FIXED_HASH_SEED
7c673cae
FG
41981/*
41982 * String hash computation (interning).
11fdf7f2
TL
41983 *
41984 * String hashing is performance critical because a string hash is computed
41985 * for all new strings which are candidates to be added to the string table.
41986 * However, strings actually added to the string table go through a codepoint
41987 * length calculation which dominates performance because it goes through
41988 * every byte of the input string (but only for strings added).
41989 *
41990 * The string hash algorithm should be fast, but on the other hand provide
41991 * good enough hashes to ensure both string table and object property table
41992 * hash tables work reasonably well (i.e., there aren't too many collisions
41993 * with real world inputs). Unless the hash is cryptographic, it's always
41994 * possible to craft inputs with maximal hash collisions.
41995 *
41996 * NOTE: The hash algorithms must match src/dukutil.py:duk_heap_hashstring()
41997 * for ROM string support!
7c673cae
FG
41998 */
41999
42000/* include removed: duk_internal.h */
42001
11fdf7f2
TL
42002#if defined(DUK_USE_STRHASH_DENSE)
42003/* Constants for duk_hashstring(). */
7c673cae
FG
42004#define DUK__STRHASH_SHORTSTRING 4096L
42005#define DUK__STRHASH_MEDIUMSTRING (256L * 1024L)
42006#define DUK__STRHASH_BLOCKSIZE 256L
42007
42008DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len) {
42009 duk_uint32_t hash;
42010
11fdf7f2
TL
42011 /* Use Murmurhash2 directly for short strings, and use "block skipping"
42012 * for long strings: hash an initial part and then sample the rest of
42013 * the string with reasonably sized chunks. An initial offset for the
42014 * sampling is computed based on a hash of the initial part of the string;
42015 * this is done to (usually) avoid the case where all long strings have
42016 * certain offset ranges which are never sampled.
7c673cae 42017 *
11fdf7f2
TL
42018 * Skip should depend on length and bound the total time to roughly
42019 * logarithmic. With current values:
7c673cae 42020 *
11fdf7f2
TL
42021 * 1M string => 256 * 241 = 61696 bytes (0.06M) of hashing
42022 * 1G string => 256 * 16321 = 4178176 bytes (3.98M) of hashing
7c673cae 42023 *
11fdf7f2
TL
42024 * XXX: It would be better to compute the skip offset more "smoothly"
42025 * instead of having a few boundary values.
7c673cae
FG
42026 */
42027
42028 /* note: mixing len into seed improves hashing when skipping */
42029 duk_uint32_t str_seed = heap->hash_seed ^ ((duk_uint32_t) len);
42030
42031 if (len <= DUK__STRHASH_SHORTSTRING) {
42032 hash = duk_util_hashbytes(str, len, str_seed);
42033 } else {
42034 duk_size_t off;
42035 duk_size_t skip;
42036
42037 if (len <= DUK__STRHASH_MEDIUMSTRING) {
42038 skip = (duk_size_t) (16 * DUK__STRHASH_BLOCKSIZE + DUK__STRHASH_BLOCKSIZE);
42039 } else {
42040 skip = (duk_size_t) (256 * DUK__STRHASH_BLOCKSIZE + DUK__STRHASH_BLOCKSIZE);
42041 }
42042
42043 hash = duk_util_hashbytes(str, (duk_size_t) DUK__STRHASH_SHORTSTRING, str_seed);
42044 off = DUK__STRHASH_SHORTSTRING + (skip * (hash % 256)) / 256;
42045
42046 /* XXX: inefficient loop */
42047 while (off < len) {
42048 duk_size_t left = len - off;
42049 duk_size_t now = (duk_size_t) (left > DUK__STRHASH_BLOCKSIZE ? DUK__STRHASH_BLOCKSIZE : left);
42050 hash ^= duk_util_hashbytes(str + off, now, str_seed);
42051 off += skip;
42052 }
42053 }
42054
42055#if defined(DUK_USE_STRHASH16)
42056 /* Truncate to 16 bits here, so that a computed hash can be compared
42057 * against a hash stored in a 16-bit field.
42058 */
42059 hash &= 0x0000ffffUL;
42060#endif
42061 return hash;
42062}
11fdf7f2
TL
42063
42064#undef DUK__STRHASH_SHORTSTRING
42065#undef DUK__STRHASH_MEDIUMSTRING
42066#undef DUK__STRHASH_BLOCKSIZE
42067#else /* DUK_USE_STRHASH_DENSE */
42068DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len) {
42069 duk_uint32_t hash;
42070 duk_size_t step;
42071 duk_size_t off;
42072
42073 /* Slightly modified "Bernstein hash" from:
42074 *
42075 * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx
42076 *
42077 * Modifications: string skipping and reverse direction similar to
42078 * Lua 5.1.5, and different hash initializer.
42079 *
42080 * The reverse direction ensures last byte it always included in the
42081 * hash which is a good default as changing parts of the string are
42082 * more often in the suffix than in the prefix.
42083 */
42084
42085 hash = heap->hash_seed ^ ((duk_uint32_t) len); /* Bernstein hash init value is normally 5381 */
42086 step = (len >> DUK_USE_STRHASH_SKIP_SHIFT) + 1;
42087 for (off = len; off >= step; off -= step) {
42088 DUK_ASSERT(off >= 1); /* off >= step, and step >= 1 */
42089 hash = (hash * 33) + str[off - 1];
42090 }
42091
42092#if defined(DUK_USE_STRHASH16)
42093 /* Truncate to 16 bits here, so that a computed hash can be compared
42094 * against a hash stored in a 16-bit field.
42095 */
42096 hash &= 0x0000ffffUL;
42097#endif
42098 return hash;
42099}
42100#endif /* DUK_USE_STRHASH_DENSE */
7c673cae
FG
42101/*
42102 * Mark-and-sweep garbage collection.
42103 */
42104
42105/* include removed: duk_internal.h */
42106
42107#ifdef DUK_USE_MARK_AND_SWEEP
42108
42109DUK_LOCAL_DECL void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h);
42110DUK_LOCAL_DECL void duk__mark_tval(duk_heap *heap, duk_tval *tv);
42111
42112/*
42113 * Misc
42114 */
42115
42116/* Select a thread for mark-and-sweep use.
42117 *
42118 * XXX: This needs to change later.
42119 */
42120DUK_LOCAL duk_hthread *duk__get_temp_hthread(duk_heap *heap) {
42121 if (heap->curr_thread) {
42122 return heap->curr_thread;
42123 }
42124 return heap->heap_thread; /* may be NULL, too */
42125}
42126
42127/*
42128 * Marking functions for heap types: mark children recursively
42129 */
42130
42131DUK_LOCAL void duk__mark_hstring(duk_heap *heap, duk_hstring *h) {
42132 DUK_UNREF(heap);
42133 DUK_UNREF(h);
42134
42135 DUK_DDD(DUK_DDDPRINT("duk__mark_hstring: %p", (void *) h));
42136 DUK_ASSERT(h);
42137
42138 /* nothing to process */
42139}
42140
42141DUK_LOCAL void duk__mark_hobject(duk_heap *heap, duk_hobject *h) {
42142 duk_uint_fast32_t i;
42143
42144 DUK_DDD(DUK_DDDPRINT("duk__mark_hobject: %p", (void *) h));
42145
42146 DUK_ASSERT(h);
42147
42148 /* XXX: use advancing pointers instead of index macros -> faster and smaller? */
42149
42150 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) {
42151 duk_hstring *key = DUK_HOBJECT_E_GET_KEY(heap, h, i);
42152 if (!key) {
42153 continue;
42154 }
42155 duk__mark_heaphdr(heap, (duk_heaphdr *) key);
42156 if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, h, i)) {
42157 duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.get);
42158 duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.set);
42159 } else {
42160 duk__mark_tval(heap, &DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->v);
42161 }
42162 }
42163
42164 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) {
42165 duk__mark_tval(heap, DUK_HOBJECT_A_GET_VALUE_PTR(heap, h, i));
42166 }
42167
42168 /* hash part is a 'weak reference' and does not contribute */
42169
42170 duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(heap, h));
42171
42172 if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
42173 duk_hcompiledfunction *f = (duk_hcompiledfunction *) h;
42174 duk_tval *tv, *tv_end;
42175 duk_hobject **fn, **fn_end;
42176
42177 /* 'data' is reachable through every compiled function which
42178 * contains a reference.
42179 */
42180
42181 duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HCOMPILEDFUNCTION_GET_DATA(heap, f));
42182
11fdf7f2
TL
42183 if (DUK_HCOMPILEDFUNCTION_GET_DATA(heap, f) != NULL) {
42184 tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(heap, f);
42185 tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(heap, f);
42186 while (tv < tv_end) {
42187 duk__mark_tval(heap, tv);
42188 tv++;
42189 }
7c673cae 42190
11fdf7f2
TL
42191 fn = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(heap, f);
42192 fn_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(heap, f);
42193 while (fn < fn_end) {
42194 duk__mark_heaphdr(heap, (duk_heaphdr *) *fn);
42195 fn++;
42196 }
42197 } else {
42198 /* May happen in some out-of-memory corner cases. */
42199 DUK_D(DUK_DPRINT("duk_hcompiledfunction 'data' is NULL, skipping marking"));
7c673cae
FG
42200 }
42201 } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
42202 duk_hnativefunction *f = (duk_hnativefunction *) h;
42203 DUK_UNREF(f);
42204 /* nothing to mark */
42205 } else if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
42206 duk_hbufferobject *b = (duk_hbufferobject *) h;
42207 duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf);
42208 } else if (DUK_HOBJECT_IS_THREAD(h)) {
42209 duk_hthread *t = (duk_hthread *) h;
42210 duk_tval *tv;
42211
42212 tv = t->valstack;
11fdf7f2 42213 while (tv < t->valstack_top) {
7c673cae
FG
42214 duk__mark_tval(heap, tv);
42215 tv++;
42216 }
42217
42218 for (i = 0; i < (duk_uint_fast32_t) t->callstack_top; i++) {
42219 duk_activation *act = t->callstack + i;
42220 duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_ACT_GET_FUNC(act));
42221 duk__mark_heaphdr(heap, (duk_heaphdr *) act->var_env);
42222 duk__mark_heaphdr(heap, (duk_heaphdr *) act->lex_env);
42223#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
42224 duk__mark_heaphdr(heap, (duk_heaphdr *) act->prev_caller);
42225#endif
42226 }
42227
42228#if 0 /* nothing now */
42229 for (i = 0; i < (duk_uint_fast32_t) t->catchstack_top; i++) {
42230 duk_catcher *cat = t->catchstack + i;
42231 }
42232#endif
42233
42234 duk__mark_heaphdr(heap, (duk_heaphdr *) t->resumer);
42235
42236 /* XXX: duk_small_uint_t would be enough for this loop */
42237 for (i = 0; i < DUK_NUM_BUILTINS; i++) {
42238 duk__mark_heaphdr(heap, (duk_heaphdr *) t->builtins[i]);
42239 }
42240 }
42241}
42242
42243/* recursion tracking happens here only */
42244DUK_LOCAL void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h) {
42245 DUK_DDD(DUK_DDDPRINT("duk__mark_heaphdr %p, type %ld",
42246 (void *) h,
42247 (h != NULL ? (long) DUK_HEAPHDR_GET_TYPE(h) : (long) -1)));
42248 if (!h) {
42249 return;
42250 }
11fdf7f2
TL
42251#if defined(DUK_USE_ROM_OBJECTS)
42252 if (DUK_HEAPHDR_HAS_READONLY(h)) {
42253 DUK_DDD(DUK_DDDPRINT("readonly object %p, skip", (void *) h));
42254 return;
42255 }
42256#endif
7c673cae
FG
42257 if (DUK_HEAPHDR_HAS_REACHABLE(h)) {
42258 DUK_DDD(DUK_DDDPRINT("already marked reachable, skip"));
42259 return;
42260 }
42261 DUK_HEAPHDR_SET_REACHABLE(h);
42262
42263 if (heap->mark_and_sweep_recursion_depth >= DUK_USE_MARK_AND_SWEEP_RECLIMIT) {
42264 /* log this with a normal debug level because this should be relatively rare */
42265 DUK_D(DUK_DPRINT("mark-and-sweep recursion limit reached, marking as temproot: %p", (void *) h));
42266 DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap);
42267 DUK_HEAPHDR_SET_TEMPROOT(h);
42268 return;
42269 }
42270
42271 heap->mark_and_sweep_recursion_depth++;
42272
42273 switch ((int) DUK_HEAPHDR_GET_TYPE(h)) {
42274 case DUK_HTYPE_STRING:
42275 duk__mark_hstring(heap, (duk_hstring *) h);
42276 break;
42277 case DUK_HTYPE_OBJECT:
42278 duk__mark_hobject(heap, (duk_hobject *) h);
42279 break;
42280 case DUK_HTYPE_BUFFER:
42281 /* nothing to mark */
42282 break;
42283 default:
42284 DUK_D(DUK_DPRINT("attempt to mark heaphdr %p with invalid htype %ld", (void *) h, (long) DUK_HEAPHDR_GET_TYPE(h)));
42285 DUK_UNREACHABLE();
42286 }
42287
42288 heap->mark_and_sweep_recursion_depth--;
42289}
42290
42291DUK_LOCAL void duk__mark_tval(duk_heap *heap, duk_tval *tv) {
42292 DUK_DDD(DUK_DDDPRINT("duk__mark_tval %p", (void *) tv));
42293 if (!tv) {
42294 return;
42295 }
42296 if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
42297 duk__mark_heaphdr(heap, DUK_TVAL_GET_HEAPHDR(tv));
42298 }
42299}
42300
42301/*
42302 * Mark the heap.
42303 */
42304
42305DUK_LOCAL void duk__mark_roots_heap(duk_heap *heap) {
42306 duk_small_uint_t i;
42307
42308 DUK_DD(DUK_DDPRINT("duk__mark_roots_heap: %p", (void *) heap));
42309
42310 duk__mark_heaphdr(heap, (duk_heaphdr *) heap->heap_thread);
42311 duk__mark_heaphdr(heap, (duk_heaphdr *) heap->heap_object);
42312
42313 for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
42314 duk_hstring *h = DUK_HEAP_GET_STRING(heap, i);
42315 duk__mark_heaphdr(heap, (duk_heaphdr *) h);
42316 }
42317
42318 duk__mark_tval(heap, &heap->lj.value1);
42319 duk__mark_tval(heap, &heap->lj.value2);
42320
42321#if defined(DUK_USE_DEBUGGER_SUPPORT)
42322 for (i = 0; i < heap->dbg_breakpoint_count; i++) {
42323 duk__mark_heaphdr(heap, (duk_heaphdr *) heap->dbg_breakpoints[i].filename);
42324 }
42325#endif
42326}
42327
42328/*
42329 * Mark refzero_list objects.
42330 *
42331 * Objects on the refzero_list have no inbound references. They might have
42332 * outbound references to objects that we might free, which would invalidate
42333 * any references held by the refzero objects. A refzero object might also
42334 * be rescued by refcount finalization. Refzero objects are treated as
42335 * reachability roots to ensure they (or anything they point to) are not
42336 * freed in mark-and-sweep.
42337 */
42338
42339#ifdef DUK_USE_REFERENCE_COUNTING
42340DUK_LOCAL void duk__mark_refzero_list(duk_heap *heap) {
42341 duk_heaphdr *hdr;
42342
42343 DUK_DD(DUK_DDPRINT("duk__mark_refzero_list: %p", (void *) heap));
42344
42345 hdr = heap->refzero_list;
42346 while (hdr) {
42347 duk__mark_heaphdr(heap, hdr);
42348 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
42349 }
42350}
42351#endif
42352
42353/*
42354 * Mark unreachable, finalizable objects.
42355 *
42356 * Such objects will be moved aside and their finalizers run later. They have
42357 * to be treated as reachability roots for their properties etc to remain
42358 * allocated. This marking is only done for unreachable values which would
42359 * be swept later (refzero_list is thus excluded).
42360 *
42361 * Objects are first marked FINALIZABLE and only then marked as reachability
42362 * roots; otherwise circular references might be handled inconsistently.
42363 */
42364
42365DUK_LOCAL void duk__mark_finalizable(duk_heap *heap) {
42366 duk_hthread *thr;
42367 duk_heaphdr *hdr;
42368 duk_size_t count_finalizable = 0;
42369
42370 DUK_DD(DUK_DDPRINT("duk__mark_finalizable: %p", (void *) heap));
42371
42372 thr = duk__get_temp_hthread(heap);
42373 DUK_ASSERT(thr != NULL);
42374
42375 hdr = heap->heap_allocated;
42376 while (hdr) {
42377 /* A finalizer is looked up from the object and up its prototype chain
42378 * (which allows inherited finalizers). A prototype loop must not cause
42379 * an error to be thrown here; duk_hobject_hasprop_raw() will ignore a
42380 * prototype loop silently and indicate that the property doesn't exist.
42381 */
42382
42383 if (!DUK_HEAPHDR_HAS_REACHABLE(hdr) &&
42384 DUK_HEAPHDR_GET_TYPE(hdr) == DUK_HTYPE_OBJECT &&
42385 !DUK_HEAPHDR_HAS_FINALIZED(hdr) &&
42386 duk_hobject_hasprop_raw(thr, (duk_hobject *) hdr, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) {
42387
42388 /* heaphdr:
42389 * - is not reachable
42390 * - is an object
42391 * - is not a finalized object
42392 * - has a finalizer
42393 */
42394
42395 DUK_DD(DUK_DDPRINT("unreachable heap object will be "
42396 "finalized -> mark as finalizable "
42397 "and treat as a reachability root: %p",
42398 (void *) hdr));
11fdf7f2 42399 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(hdr));
7c673cae
FG
42400 DUK_HEAPHDR_SET_FINALIZABLE(hdr);
42401 count_finalizable ++;
42402 }
42403
42404 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
42405 }
42406
42407 if (count_finalizable == 0) {
42408 return;
42409 }
42410
42411 DUK_DD(DUK_DDPRINT("marked %ld heap objects as finalizable, now mark them reachable",
42412 (long) count_finalizable));
42413
42414 hdr = heap->heap_allocated;
42415 while (hdr) {
42416 if (DUK_HEAPHDR_HAS_FINALIZABLE(hdr)) {
42417 duk__mark_heaphdr(heap, hdr);
42418 }
42419
42420 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
42421 }
42422
42423 /* Caller will finish the marking process if we hit a recursion limit. */
42424}
42425
42426/*
42427 * Mark objects on finalize_list.
42428 *
42429 */
42430
42431DUK_LOCAL void duk__mark_finalize_list(duk_heap *heap) {
42432 duk_heaphdr *hdr;
42433#ifdef DUK_USE_DEBUG
42434 duk_size_t count_finalize_list = 0;
42435#endif
42436
42437 DUK_DD(DUK_DDPRINT("duk__mark_finalize_list: %p", (void *) heap));
42438
42439 hdr = heap->finalize_list;
42440 while (hdr) {
42441 duk__mark_heaphdr(heap, hdr);
42442 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
42443#ifdef DUK_USE_DEBUG
42444 count_finalize_list++;
42445#endif
42446 }
42447
42448#ifdef DUK_USE_DEBUG
42449 if (count_finalize_list > 0) {
42450 DUK_D(DUK_DPRINT("marked %ld objects on the finalize_list as reachable (previous finalizer run skipped)",
42451 (long) count_finalize_list));
42452 }
42453#endif
42454}
42455
42456/*
42457 * Fallback marking handler if recursion limit is reached.
42458 *
42459 * Iterates 'temproots' until recursion limit is no longer hit. Note
42460 * that temproots may reside either in heap allocated list or the
42461 * refzero work list. This is a slow scan, but guarantees that we
42462 * finish with a bounded C stack.
42463 *
42464 * Note that nodes may have been marked as temproots before this
42465 * scan begun, OR they may have been marked during the scan (as
42466 * we process nodes recursively also during the scan). This is
42467 * intended behavior.
42468 */
42469
42470#ifdef DUK_USE_DEBUG
42471DUK_LOCAL void duk__handle_temproot(duk_heap *heap, duk_heaphdr *hdr, duk_size_t *count) {
42472#else
42473DUK_LOCAL void duk__handle_temproot(duk_heap *heap, duk_heaphdr *hdr) {
42474#endif
42475 if (!DUK_HEAPHDR_HAS_TEMPROOT(hdr)) {
42476 DUK_DDD(DUK_DDDPRINT("not a temp root: %p", (void *) hdr));
42477 return;
42478 }
42479
42480 DUK_DDD(DUK_DDDPRINT("found a temp root: %p", (void *) hdr));
42481 DUK_HEAPHDR_CLEAR_TEMPROOT(hdr);
42482 DUK_HEAPHDR_CLEAR_REACHABLE(hdr); /* done so that duk__mark_heaphdr() works correctly */
42483 duk__mark_heaphdr(heap, hdr);
42484
42485#ifdef DUK_USE_DEBUG
42486 (*count)++;
42487#endif
42488}
42489
42490DUK_LOCAL void duk__mark_temproots_by_heap_scan(duk_heap *heap) {
42491 duk_heaphdr *hdr;
42492#ifdef DUK_USE_DEBUG
42493 duk_size_t count;
42494#endif
42495
42496 DUK_DD(DUK_DDPRINT("duk__mark_temproots_by_heap_scan: %p", (void *) heap));
42497
42498 while (DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap)) {
42499 DUK_DD(DUK_DDPRINT("recursion limit reached, doing heap scan to continue from temproots"));
42500
42501#ifdef DUK_USE_DEBUG
42502 count = 0;
42503#endif
42504 DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap);
42505
42506 hdr = heap->heap_allocated;
42507 while (hdr) {
42508#ifdef DUK_USE_DEBUG
42509 duk__handle_temproot(heap, hdr, &count);
42510#else
42511 duk__handle_temproot(heap, hdr);
42512#endif
42513 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
42514 }
42515
42516 /* must also check refzero_list */
42517#ifdef DUK_USE_REFERENCE_COUNTING
42518 hdr = heap->refzero_list;
42519 while (hdr) {
42520#ifdef DUK_USE_DEBUG
42521 duk__handle_temproot(heap, hdr, &count);
42522#else
42523 duk__handle_temproot(heap, hdr);
42524#endif
42525 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
42526 }
42527#endif /* DUK_USE_REFERENCE_COUNTING */
42528
42529#ifdef DUK_USE_DEBUG
42530 DUK_DD(DUK_DDPRINT("temproot mark heap scan processed %ld temp roots", (long) count));
42531#endif
42532 }
42533}
42534
42535/*
42536 * Finalize refcounts for heap elements just about to be freed.
42537 * This must be done for all objects before freeing to avoid any
42538 * stale pointer dereferences.
42539 *
42540 * Note that this must deduce the set of objects to be freed
42541 * identically to duk__sweep_heap().
42542 */
42543
42544#ifdef DUK_USE_REFERENCE_COUNTING
42545DUK_LOCAL void duk__finalize_refcounts(duk_heap *heap) {
42546 duk_hthread *thr;
42547 duk_heaphdr *hdr;
42548
42549 thr = duk__get_temp_hthread(heap);
42550 DUK_ASSERT(thr != NULL);
42551
42552 DUK_DD(DUK_DDPRINT("duk__finalize_refcounts: heap=%p, hthread=%p",
42553 (void *) heap, (void *) thr));
42554
42555 hdr = heap->heap_allocated;
42556 while (hdr) {
42557 if (!DUK_HEAPHDR_HAS_REACHABLE(hdr)) {
42558 /*
42559 * Unreachable object about to be swept. Finalize target refcounts
42560 * (objects which the unreachable object points to) without doing
42561 * refzero processing. Recursive decrefs are also prevented when
42562 * refzero processing is disabled.
42563 *
42564 * Value cannot be a finalizable object, as they have been made
42565 * temporarily reachable for this round.
42566 */
42567
42568 DUK_DDD(DUK_DDDPRINT("unreachable object, refcount finalize before sweeping: %p", (void *) hdr));
42569 duk_heaphdr_refcount_finalize(thr, hdr);
42570 }
42571
42572 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
42573 }
42574}
42575#endif /* DUK_USE_REFERENCE_COUNTING */
42576
42577/*
42578 * Clear (reachable) flags of refzero work list.
42579 */
42580
42581#ifdef DUK_USE_REFERENCE_COUNTING
42582DUK_LOCAL void duk__clear_refzero_list_flags(duk_heap *heap) {
42583 duk_heaphdr *hdr;
42584
42585 DUK_DD(DUK_DDPRINT("duk__clear_refzero_list_flags: %p", (void *) heap));
42586
42587 hdr = heap->refzero_list;
42588 while (hdr) {
42589 DUK_HEAPHDR_CLEAR_REACHABLE(hdr);
42590 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr));
11fdf7f2 42591 /* DUK_HEAPHDR_HAS_FINALIZED may or may not be set. */
7c673cae
FG
42592 DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr));
42593 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
42594 }
42595}
42596#endif /* DUK_USE_REFERENCE_COUNTING */
42597
42598/*
42599 * Clear (reachable) flags of finalize_list
42600 *
42601 * We could mostly do in the sweep phase when we move objects from the
42602 * heap into the finalize_list. However, if a finalizer run is skipped
42603 * during a mark-and-sweep, the objects on the finalize_list will be marked
42604 * reachable during the next mark-and-sweep. Since they're already on the
42605 * finalize_list, no-one will be clearing their REACHABLE flag so we do it
42606 * here. (This now overlaps with the sweep handling in a harmless way.)
42607 */
42608
42609DUK_LOCAL void duk__clear_finalize_list_flags(duk_heap *heap) {
42610 duk_heaphdr *hdr;
42611
42612 DUK_DD(DUK_DDPRINT("duk__clear_finalize_list_flags: %p", (void *) heap));
42613
42614 hdr = heap->finalize_list;
42615 while (hdr) {
42616 DUK_HEAPHDR_CLEAR_REACHABLE(hdr);
42617 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr));
42618 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr));
42619 DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr));
42620 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
42621 }
42622}
42623
42624/*
42625 * Sweep stringtable
42626 */
42627
42628#if defined(DUK_USE_STRTAB_CHAIN)
42629
42630/* XXX: skip count_free w/o debug? */
42631#if defined(DUK_USE_HEAPPTR16)
42632DUK_LOCAL void duk__sweep_string_chain16(duk_heap *heap, duk_uint16_t *slot, duk_size_t *count_keep, duk_size_t *count_free) {
42633 duk_uint16_t h16 = *slot;
42634 duk_hstring *h;
42635 duk_uint16_t null16 = heap->heapptr_null16;
42636
42637 if (h16 == null16) {
42638 /* nop */
42639 return;
42640 }
42641 h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, h16);
42642 DUK_ASSERT(h != NULL);
42643
42644 if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) {
42645 DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h);
42646 (*count_keep)++;
42647 } else {
42648#if defined(DUK_USE_REFERENCE_COUNTING)
42649 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0);
42650#endif
42651 /* deal with weak references first */
42652 duk_heap_strcache_string_remove(heap, (duk_hstring *) h);
42653 *slot = null16;
42654
42655 /* free inner references (these exist e.g. when external
42656 * strings are enabled)
42657 */
42658 duk_free_hstring_inner(heap, h);
42659 DUK_FREE(heap, h);
42660 (*count_free)++;
42661 }
42662}
42663#else /* DUK_USE_HEAPPTR16 */
42664DUK_LOCAL void duk__sweep_string_chain(duk_heap *heap, duk_hstring **slot, duk_size_t *count_keep, duk_size_t *count_free) {
42665 duk_hstring *h = *slot;
42666
42667 if (h == NULL) {
42668 /* nop */
42669 return;
42670 }
42671
42672 if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) {
42673 DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h);
42674 (*count_keep)++;
42675 } else {
42676#if defined(DUK_USE_REFERENCE_COUNTING)
42677 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0);
42678#endif
42679 /* deal with weak references first */
42680 duk_heap_strcache_string_remove(heap, (duk_hstring *) h);
42681 *slot = NULL;
42682
42683 /* free inner references (these exist e.g. when external
42684 * strings are enabled)
42685 */
42686 duk_free_hstring_inner(heap, h);
42687 DUK_FREE(heap, h);
42688 (*count_free)++;
42689 }
42690}
42691#endif /* DUK_USE_HEAPPTR16 */
42692
42693DUK_LOCAL void duk__sweep_stringtable_chain(duk_heap *heap, duk_size_t *out_count_keep) {
42694 duk_strtab_entry *e;
42695 duk_uint_fast32_t i;
42696 duk_size_t count_free = 0;
42697 duk_size_t count_keep = 0;
42698 duk_size_t j, n;
42699#if defined(DUK_USE_HEAPPTR16)
42700 duk_uint16_t *lst;
42701#else
42702 duk_hstring **lst;
42703#endif
42704
42705 DUK_DD(DUK_DDPRINT("duk__sweep_stringtable: %p", (void *) heap));
42706
42707 /* Non-zero refcounts should not happen for unreachable strings,
42708 * because we refcount finalize all unreachable objects which
42709 * should have decreased unreachable string refcounts to zero
42710 * (even for cycles).
42711 */
42712
42713 for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
42714 e = heap->strtable + i;
42715 if (e->listlen == 0) {
42716#if defined(DUK_USE_HEAPPTR16)
42717 duk__sweep_string_chain16(heap, &e->u.str16, &count_keep, &count_free);
42718#else
42719 duk__sweep_string_chain(heap, &e->u.str, &count_keep, &count_free);
42720#endif
42721 } else {
42722#if defined(DUK_USE_HEAPPTR16)
42723 lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
42724#else
42725 lst = e->u.strlist;
42726#endif
42727 for (j = 0, n = e->listlen; j < n; j++) {
42728#if defined(DUK_USE_HEAPPTR16)
42729 duk__sweep_string_chain16(heap, lst + j, &count_keep, &count_free);
42730#else
42731 duk__sweep_string_chain(heap, lst + j, &count_keep, &count_free);
42732#endif
42733 }
42734 }
42735 }
42736
42737 DUK_D(DUK_DPRINT("mark-and-sweep sweep stringtable: %ld freed, %ld kept",
42738 (long) count_free, (long) count_keep));
42739 *out_count_keep = count_keep;
42740}
42741#endif /* DUK_USE_STRTAB_CHAIN */
42742
42743#if defined(DUK_USE_STRTAB_PROBE)
42744DUK_LOCAL void duk__sweep_stringtable_probe(duk_heap *heap, duk_size_t *out_count_keep) {
42745 duk_hstring *h;
42746 duk_uint_fast32_t i;
42747#ifdef DUK_USE_DEBUG
42748 duk_size_t count_free = 0;
42749#endif
42750 duk_size_t count_keep = 0;
42751
42752 DUK_DD(DUK_DDPRINT("duk__sweep_stringtable: %p", (void *) heap));
42753
42754 for (i = 0; i < heap->st_size; i++) {
42755#if defined(DUK_USE_HEAPPTR16)
11fdf7f2 42756 h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]);
7c673cae
FG
42757#else
42758 h = heap->strtable[i];
42759#endif
42760 if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) {
42761 continue;
42762 } else if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) {
42763 DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h);
42764 count_keep++;
42765 continue;
42766 }
42767
42768#ifdef DUK_USE_DEBUG
42769 count_free++;
42770#endif
42771
42772#if defined(DUK_USE_REFERENCE_COUNTING)
42773 /* Non-zero refcounts should not happen for unreachable strings,
42774 * because we refcount finalize all unreachable objects which
42775 * should have decreased unreachable string refcounts to zero
42776 * (even for cycles).
42777 */
42778 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0);
42779#endif
42780
42781 DUK_DDD(DUK_DDDPRINT("sweep string, not reachable: %p", (void *) h));
42782
42783 /* deal with weak references first */
42784 duk_heap_strcache_string_remove(heap, (duk_hstring *) h);
42785
42786 /* remove the string (mark DELETED), could also call
42787 * duk_heap_string_remove() but that would be slow and
42788 * pointless because we already know the slot.
42789 */
42790#if defined(DUK_USE_HEAPPTR16)
42791 heap->strtable16[i] = heap->heapptr_deleted16;
42792#else
42793 heap->strtable[i] = DUK_STRTAB_DELETED_MARKER(heap);
42794#endif
42795
42796 /* free inner references (these exist e.g. when external
42797 * strings are enabled)
42798 */
42799 duk_free_hstring_inner(heap, (duk_hstring *) h);
42800
42801 /* finally free the struct itself */
42802 DUK_FREE(heap, h);
42803 }
42804
42805#ifdef DUK_USE_DEBUG
42806 DUK_D(DUK_DPRINT("mark-and-sweep sweep stringtable: %ld freed, %ld kept",
42807 (long) count_free, (long) count_keep));
42808#endif
42809 *out_count_keep = count_keep;
42810}
42811#endif /* DUK_USE_STRTAB_PROBE */
42812
42813/*
42814 * Sweep heap
42815 */
42816
42817DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_int_t flags, duk_size_t *out_count_keep) {
42818 duk_heaphdr *prev; /* last element that was left in the heap */
42819 duk_heaphdr *curr;
42820 duk_heaphdr *next;
42821#ifdef DUK_USE_DEBUG
42822 duk_size_t count_free = 0;
42823 duk_size_t count_finalize = 0;
42824 duk_size_t count_rescue = 0;
42825#endif
42826 duk_size_t count_keep = 0;
42827
42828 DUK_UNREF(flags);
42829 DUK_DD(DUK_DDPRINT("duk__sweep_heap: %p", (void *) heap));
42830
42831 prev = NULL;
42832 curr = heap->heap_allocated;
42833 heap->heap_allocated = NULL;
42834 while (curr) {
11fdf7f2 42835 /* Strings and ROM objects are never placed on the heap allocated list. */
7c673cae 42836 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) != DUK_HTYPE_STRING);
11fdf7f2 42837 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(curr));
7c673cae
FG
42838
42839 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
42840
42841 if (DUK_HEAPHDR_HAS_REACHABLE(curr)) {
42842 /*
42843 * Reachable object, keep
42844 */
42845
42846 DUK_DDD(DUK_DDDPRINT("sweep, reachable: %p", (void *) curr));
42847
42848 if (DUK_HEAPHDR_HAS_FINALIZABLE(curr)) {
42849 /*
42850 * If object has been marked finalizable, move it to the
42851 * "to be finalized" work list. It will be collected on
42852 * the next mark-and-sweep if it is still unreachable
42853 * after running the finalizer.
42854 */
42855
42856 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
42857 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT);
42858 DUK_DDD(DUK_DDDPRINT("object has finalizer, move to finalization work list: %p", (void *) curr));
42859
42860#ifdef DUK_USE_DOUBLE_LINKED_HEAP
42861 if (heap->finalize_list) {
42862 DUK_HEAPHDR_SET_PREV(heap, heap->finalize_list, curr);
42863 }
42864 DUK_HEAPHDR_SET_PREV(heap, curr, NULL);
42865#endif
42866 DUK_HEAPHDR_SET_NEXT(heap, curr, heap->finalize_list);
11fdf7f2 42867 DUK_ASSERT_HEAPHDR_LINKS(heap, curr);
7c673cae
FG
42868 heap->finalize_list = curr;
42869#ifdef DUK_USE_DEBUG
42870 count_finalize++;
42871#endif
42872 } else {
42873 /*
42874 * Object will be kept; queue object back to heap_allocated (to tail)
42875 */
42876
42877 if (DUK_HEAPHDR_HAS_FINALIZED(curr)) {
42878 /*
42879 * Object's finalizer was executed on last round, and
42880 * object has been happily rescued.
42881 */
42882
42883 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
42884 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT);
42885 DUK_DD(DUK_DDPRINT("object rescued during mark-and-sweep finalization: %p", (void *) curr));
42886#ifdef DUK_USE_DEBUG
42887 count_rescue++;
42888#endif
42889 } else {
42890 /*
42891 * Plain, boring reachable object.
42892 */
11fdf7f2 42893 DUK_DD(DUK_DDPRINT("keep object: %!iO", curr));
7c673cae
FG
42894 count_keep++;
42895 }
42896
42897 if (!heap->heap_allocated) {
42898 heap->heap_allocated = curr;
42899 }
42900 if (prev) {
42901 DUK_HEAPHDR_SET_NEXT(heap, prev, curr);
42902 }
42903#ifdef DUK_USE_DOUBLE_LINKED_HEAP
42904 DUK_HEAPHDR_SET_PREV(heap, curr, prev);
42905#endif
11fdf7f2
TL
42906 DUK_ASSERT_HEAPHDR_LINKS(heap, prev);
42907 DUK_ASSERT_HEAPHDR_LINKS(heap, curr);
7c673cae
FG
42908 prev = curr;
42909 }
42910
42911 DUK_HEAPHDR_CLEAR_REACHABLE(curr);
42912 DUK_HEAPHDR_CLEAR_FINALIZED(curr);
42913 DUK_HEAPHDR_CLEAR_FINALIZABLE(curr);
42914
42915 DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr));
42916 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
42917 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
42918
42919 curr = next;
42920 } else {
42921 /*
42922 * Unreachable object, free
42923 */
42924
42925 DUK_DDD(DUK_DDDPRINT("sweep, not reachable: %p", (void *) curr));
42926
42927#if defined(DUK_USE_REFERENCE_COUNTING)
42928 /* Non-zero refcounts should not happen because we refcount
42929 * finalize all unreachable objects which should cancel out
42930 * refcounts (even for cycles).
42931 */
42932 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) == 0);
42933#endif
42934 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
42935
42936 if (DUK_HEAPHDR_HAS_FINALIZED(curr)) {
42937 DUK_DDD(DUK_DDDPRINT("finalized object not rescued: %p", (void *) curr));
42938 }
42939
42940 /* Note: object cannot be a finalizable unreachable object, as
42941 * they have been marked temporarily reachable for this round,
42942 * and are handled above.
42943 */
42944
42945#ifdef DUK_USE_DEBUG
42946 count_free++;
42947#endif
42948
42949 /* weak refs should be handled here, but no weak refs for
42950 * any non-string objects exist right now.
42951 */
42952
42953 /* free object and all auxiliary (non-heap) allocs */
42954 duk_heap_free_heaphdr_raw(heap, curr);
42955
42956 curr = next;
42957 }
42958 }
42959 if (prev) {
42960 DUK_HEAPHDR_SET_NEXT(heap, prev, NULL);
42961 }
11fdf7f2 42962 DUK_ASSERT_HEAPHDR_LINKS(heap, prev);
7c673cae
FG
42963
42964#ifdef DUK_USE_DEBUG
42965 DUK_D(DUK_DPRINT("mark-and-sweep sweep objects (non-string): %ld freed, %ld kept, %ld rescued, %ld queued for finalization",
42966 (long) count_free, (long) count_keep, (long) count_rescue, (long) count_finalize));
42967#endif
42968 *out_count_keep = count_keep;
42969}
42970
42971/*
42972 * Run (object) finalizers in the "to be finalized" work list.
42973 */
42974
11fdf7f2 42975DUK_LOCAL void duk__run_object_finalizers(duk_heap *heap, duk_small_uint_t flags) {
7c673cae
FG
42976 duk_heaphdr *curr;
42977 duk_heaphdr *next;
42978#ifdef DUK_USE_DEBUG
42979 duk_size_t count = 0;
42980#endif
42981 duk_hthread *thr;
42982
42983 DUK_DD(DUK_DDPRINT("duk__run_object_finalizers: %p", (void *) heap));
42984
42985 thr = duk__get_temp_hthread(heap);
42986 DUK_ASSERT(thr != NULL);
42987
42988 curr = heap->finalize_list;
42989 while (curr) {
42990 DUK_DDD(DUK_DDDPRINT("mark-and-sweep finalize: %p", (void *) curr));
42991
42992 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); /* only objects have finalizers */
42993 DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr)); /* flags have been already cleared */
42994 DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(curr));
42995 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
42996 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
11fdf7f2 42997 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(curr)); /* No finalizers for ROM objects */
7c673cae 42998
11fdf7f2
TL
42999 /* Keep heap->finalize_list up-to-date during the list walk.
43000 * This has no functional impact, but does matter e.g. for
43001 * duk_push_heapptr() asserts when assertions are enabled.
7c673cae 43002 */
11fdf7f2
TL
43003 heap->finalize_list = curr;
43004
43005 if (DUK_LIKELY((flags & DUK_MS_FLAG_SKIP_FINALIZERS) == 0)) {
43006 /* Run the finalizer, duk_hobject_run_finalizer() sets FINALIZED.
43007 * Next mark-and-sweep will collect the object unless it has
43008 * become reachable (i.e. rescued). FINALIZED prevents the
43009 * finalizer from being executed again before that.
43010 */
43011 duk_hobject_run_finalizer(thr, (duk_hobject *) curr); /* must never longjmp */
43012 DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(curr));
43013
43014 /* XXX: could clear FINALIZED already here; now cleared in
43015 * next mark-and-sweep.
43016 */
43017 } else {
43018 /* Used during heap destruction: don't actually run finalizers
43019 * because we're heading into forced finalization. Instead,
43020 * queue finalizable objects back to the heap_allocated list.
43021 */
43022 DUK_D(DUK_DPRINT("skip finalizers flag set, queue object to heap_allocated without finalizing"));
43023 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
43024 }
7c673cae
FG
43025
43026 /* queue back to heap_allocated */
43027 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
43028 DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, curr);
43029
43030 curr = next;
43031#ifdef DUK_USE_DEBUG
43032 count++;
43033#endif
43034 }
43035
43036 /* finalize_list will always be processed completely */
43037 heap->finalize_list = NULL;
43038
43039#ifdef DUK_USE_DEBUG
43040 DUK_D(DUK_DPRINT("mark-and-sweep finalize objects: %ld finalizers called", (long) count));
43041#endif
43042}
43043
43044/*
43045 * Object compaction.
43046 *
43047 * Compaction is assumed to never throw an error.
43048 */
43049
43050DUK_LOCAL int duk__protected_compact_object(duk_context *ctx) {
43051 /* XXX: for threads, compact value stack, call stack, catch stack? */
43052
43053 duk_hobject *obj = duk_get_hobject(ctx, -1);
43054 DUK_ASSERT(obj != NULL);
43055 duk_hobject_compact_props((duk_hthread *) ctx, obj);
43056 return 0;
43057}
43058
43059#ifdef DUK_USE_DEBUG
43060DUK_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) {
43061#else
43062DUK_LOCAL void duk__compact_object_list(duk_heap *heap, duk_hthread *thr, duk_heaphdr *start) {
43063#endif
43064 duk_heaphdr *curr;
43065#ifdef DUK_USE_DEBUG
43066 duk_size_t old_size, new_size;
43067#endif
43068 duk_hobject *obj;
43069
43070 DUK_UNREF(heap);
43071
43072 curr = start;
43073 while (curr) {
43074 DUK_DDD(DUK_DDDPRINT("mark-and-sweep compact: %p", (void *) curr));
43075
43076 if (DUK_HEAPHDR_GET_TYPE(curr) != DUK_HTYPE_OBJECT) {
43077 goto next;
43078 }
43079 obj = (duk_hobject *) curr;
43080
43081#ifdef DUK_USE_DEBUG
43082 old_size = DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj),
43083 DUK_HOBJECT_GET_ASIZE(obj),
43084 DUK_HOBJECT_GET_HSIZE(obj));
43085#endif
43086
43087 DUK_DD(DUK_DDPRINT("compact object: %p", (void *) obj));
43088 duk_push_hobject((duk_context *) thr, obj);
43089 /* XXX: disable error handlers for duration of compaction? */
43090 duk_safe_call((duk_context *) thr, duk__protected_compact_object, 1, 0);
43091
43092#ifdef DUK_USE_DEBUG
43093 new_size = DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj),
43094 DUK_HOBJECT_GET_ASIZE(obj),
43095 DUK_HOBJECT_GET_HSIZE(obj));
43096#endif
43097
43098#ifdef DUK_USE_DEBUG
43099 (*p_count_compact)++;
43100 (*p_count_bytes_saved) += (duk_size_t) (old_size - new_size);
43101#endif
43102
43103 next:
43104 curr = DUK_HEAPHDR_GET_NEXT(heap, curr);
43105#ifdef DUK_USE_DEBUG
43106 (*p_count_check)++;
43107#endif
43108 }
43109}
43110
43111DUK_LOCAL void duk__compact_objects(duk_heap *heap) {
43112 /* XXX: which lists should participate? to be finalized? */
43113#ifdef DUK_USE_DEBUG
43114 duk_size_t count_check = 0;
43115 duk_size_t count_compact = 0;
43116 duk_size_t count_bytes_saved = 0;
43117#endif
43118 duk_hthread *thr;
43119
43120 DUK_DD(DUK_DDPRINT("duk__compact_objects: %p", (void *) heap));
43121
43122 thr = duk__get_temp_hthread(heap);
43123 DUK_ASSERT(thr != NULL);
43124
43125#ifdef DUK_USE_DEBUG
43126 duk__compact_object_list(heap, thr, heap->heap_allocated, &count_check, &count_compact, &count_bytes_saved);
43127 duk__compact_object_list(heap, thr, heap->finalize_list, &count_check, &count_compact, &count_bytes_saved);
43128#ifdef DUK_USE_REFERENCE_COUNTING
43129 duk__compact_object_list(heap, thr, heap->refzero_list, &count_check, &count_compact, &count_bytes_saved);
43130#endif
43131#else
43132 duk__compact_object_list(heap, thr, heap->heap_allocated);
43133 duk__compact_object_list(heap, thr, heap->finalize_list);
43134#ifdef DUK_USE_REFERENCE_COUNTING
43135 duk__compact_object_list(heap, thr, heap->refzero_list);
43136#endif
43137#endif
43138
43139#ifdef DUK_USE_DEBUG
43140 DUK_D(DUK_DPRINT("mark-and-sweep compact objects: %ld checked, %ld compaction attempts, %ld bytes saved by compaction",
43141 (long) count_check, (long) count_compact, (long) count_bytes_saved));
43142#endif
43143}
43144
43145/*
43146 * Assertion helpers.
43147 */
43148
43149#ifdef DUK_USE_ASSERTIONS
43150DUK_LOCAL void duk__assert_heaphdr_flags(duk_heap *heap) {
43151 duk_heaphdr *hdr;
43152
43153 hdr = heap->heap_allocated;
43154 while (hdr) {
43155 DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(hdr));
43156 DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr));
43157 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr));
43158 /* may have FINALIZED */
43159 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
43160 }
43161
43162#ifdef DUK_USE_REFERENCE_COUNTING
43163 hdr = heap->refzero_list;
43164 while (hdr) {
43165 DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(hdr));
43166 DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr));
43167 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr));
11fdf7f2
TL
43168 /* DUK_HEAPHDR_HAS_FINALIZED may be set if we're doing a
43169 * refzero finalization and mark-and-sweep gets triggered
43170 * during the finalizer.
43171 */
43172 /* DUK_HEAPHDR_HAS_FINALIZED may or may not be set. */
7c673cae
FG
43173 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
43174 }
43175#endif /* DUK_USE_REFERENCE_COUNTING */
43176}
43177
43178#ifdef DUK_USE_REFERENCE_COUNTING
43179DUK_LOCAL void duk__assert_valid_refcounts(duk_heap *heap) {
43180 duk_heaphdr *hdr = heap->heap_allocated;
43181 while (hdr) {
43182 if (DUK_HEAPHDR_GET_REFCOUNT(hdr) == 0 &&
43183 DUK_HEAPHDR_HAS_FINALIZED(hdr)) {
43184 /* An object may be in heap_allocated list with a zero
43185 * refcount if it has just been finalized and is waiting
43186 * to be collected by the next cycle.
43187 */
43188 } else if (DUK_HEAPHDR_GET_REFCOUNT(hdr) == 0) {
43189 /* An object may be in heap_allocated list with a zero
43190 * refcount also if it is a temporary object created by
43191 * a finalizer; because finalization now runs inside
43192 * mark-and-sweep, such objects will not be queued to
43193 * refzero_list and will thus appear here with refcount
43194 * zero.
43195 */
43196#if 0 /* this case can no longer occur because refcount is unsigned */
43197 } else if (DUK_HEAPHDR_GET_REFCOUNT(hdr) < 0) {
43198 DUK_D(DUK_DPRINT("invalid refcount: %ld, %p -> %!O",
43199 (hdr != NULL ? (long) DUK_HEAPHDR_GET_REFCOUNT(hdr) : (long) 0),
43200 (void *) hdr, (duk_heaphdr *) hdr));
43201 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(hdr) > 0);
43202#endif
43203 }
43204 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
43205 }
43206}
43207#endif /* DUK_USE_REFERENCE_COUNTING */
43208#endif /* DUK_USE_ASSERTIONS */
43209
43210/*
43211 * Finalizer torture. Do one fake finalizer call which causes side effects
43212 * similar to one or more finalizers on actual objects.
43213 */
43214
43215#if defined(DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE)
43216DUK_LOCAL duk_ret_t duk__markandsweep_fake_finalizer(duk_context *ctx) {
43217 DUK_D(DUK_DPRINT("fake mark-and-sweep torture finalizer executed"));
43218
43219 /* Require a lot of stack to force a value stack grow/shrink.
43220 * Recursive mark-and-sweep is prevented by allocation macros
43221 * so this won't trigger another mark-and-sweep.
43222 */
43223 duk_require_stack(ctx, 100000);
43224
43225 /* XXX: do something to force a callstack grow/shrink, perhaps
43226 * just a manual forced resize or a forced relocating realloc?
43227 */
43228
43229 return 0;
43230}
43231
43232DUK_LOCAL void duk__markandsweep_torture_finalizer(duk_hthread *thr) {
43233 duk_context *ctx;
43234 duk_int_t rc;
43235
43236 DUK_ASSERT(thr != NULL);
43237 ctx = (duk_context *) thr;
43238
43239 /* Avoid fake finalization when callstack limit has been reached.
43240 * Otherwise a callstack limit error will be created, then refzero'ed.
43241 */
43242 if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit ||
43243 thr->callstack_size + 2 * DUK_CALLSTACK_GROW_STEP >= thr->callstack_max /*approximate*/) {
43244 DUK_D(DUK_DPRINT("call recursion depth reached, avoid fake mark-and-sweep torture finalizer"));
43245 return;
43246 }
43247
43248 /* Run fake finalizer. Avoid creating unnecessary garbage. */
43249 duk_push_c_function(ctx, duk__markandsweep_fake_finalizer, 0 /*nargs*/);
43250 rc = duk_pcall(ctx, 0 /*nargs*/);
43251 DUK_UNREF(rc); /* ignored */
43252 duk_pop(ctx);
43253}
43254#endif /* DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE */
43255
43256/*
43257 * Main mark-and-sweep function.
43258 *
43259 * 'flags' represents the features requested by the caller. The current
43260 * heap->mark_and_sweep_base_flags is ORed automatically into the flags;
43261 * the base flags mask typically prevents certain mark-and-sweep operations
43262 * to avoid trouble.
43263 */
43264
43265DUK_INTERNAL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags) {
43266 duk_hthread *thr;
43267 duk_size_t count_keep_obj;
43268 duk_size_t count_keep_str;
43269#ifdef DUK_USE_VOLUNTARY_GC
43270 duk_size_t tmp;
43271#endif
43272
11fdf7f2
TL
43273 if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
43274 DUK_D(DUK_DPRINT("refuse to do a recursive mark-and-sweep"));
43275 return 0;
43276 }
43277
7c673cae
FG
43278 /* XXX: thread selection for mark-and-sweep is currently a hack.
43279 * If we don't have a thread, the entire mark-and-sweep is now
43280 * skipped (although we could just skip finalizations).
43281 */
11fdf7f2
TL
43282
43283 /* If thr != NULL, the thr may still be in the middle of
43284 * initialization.
43285 * XXX: Improve the thread viability test.
7c673cae
FG
43286 */
43287 thr = duk__get_temp_hthread(heap);
43288 if (thr == NULL) {
11fdf7f2 43289 DUK_D(DUK_DPRINT("gc skipped because we don't have a temp thread"));
7c673cae
FG
43290
43291 /* reset voluntary gc trigger count */
43292#ifdef DUK_USE_VOLUNTARY_GC
43293 heap->mark_and_sweep_trigger_counter = DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP;
43294#endif
43295 return 0; /* OK */
43296 }
43297
11fdf7f2
TL
43298 /* If debugger is paused, garbage collection is disabled by default. */
43299 /* XXX: will need a force flag if garbage collection is triggered
43300 * explicitly during paused state.
43301 */
43302#if defined(DUK_USE_DEBUGGER_SUPPORT)
43303 if (DUK_HEAP_IS_PAUSED(heap)) {
43304 /* Checking this here rather that in memory alloc primitives
43305 * reduces checking code there but means a failed allocation
43306 * will go through a few retries before giving up. That's
43307 * fine because this only happens during debugging.
43308 */
43309 DUK_D(DUK_DPRINT("gc skipped because debugger is paused"));
43310 return 0;
43311 }
43312#endif
43313
7c673cae
FG
43314 DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) starting, requested flags: 0x%08lx, effective flags: 0x%08lx",
43315 (unsigned long) flags, (unsigned long) (flags | heap->mark_and_sweep_base_flags)));
43316
43317 flags |= heap->mark_and_sweep_base_flags;
43318
43319 /*
43320 * Assertions before
43321 */
43322
43323#ifdef DUK_USE_ASSERTIONS
43324 DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap));
43325 DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap));
43326 DUK_ASSERT(heap->mark_and_sweep_recursion_depth == 0);
43327 duk__assert_heaphdr_flags(heap);
43328#ifdef DUK_USE_REFERENCE_COUNTING
43329 /* Note: DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) may be true; a refcount
43330 * finalizer may trigger a mark-and-sweep.
43331 */
43332 duk__assert_valid_refcounts(heap);
43333#endif /* DUK_USE_REFERENCE_COUNTING */
43334#endif /* DUK_USE_ASSERTIONS */
43335
43336 /*
43337 * Begin
43338 */
43339
43340 DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap);
43341
43342 /*
43343 * Mark roots, hoping that recursion limit is not normally hit.
43344 * If recursion limit is hit, run additional reachability rounds
43345 * starting from "temproots" until marking is complete.
43346 *
43347 * Marking happens in two phases: first we mark actual reachability
43348 * roots (and run "temproots" to complete the process). Then we
43349 * check which objects are unreachable and are finalizable; such
43350 * objects are marked as FINALIZABLE and marked as reachability
43351 * (and "temproots" is run again to complete the process).
43352 *
43353 * The heap finalize_list must also be marked as a reachability root.
43354 * There may be objects on the list from a previous round if the
43355 * previous run had finalizer skip flag.
43356 */
43357
43358 duk__mark_roots_heap(heap); /* main reachability roots */
43359#ifdef DUK_USE_REFERENCE_COUNTING
43360 duk__mark_refzero_list(heap); /* refzero_list treated as reachability roots */
43361#endif
43362 duk__mark_temproots_by_heap_scan(heap); /* temproots */
43363
43364 duk__mark_finalizable(heap); /* mark finalizable as reachability roots */
43365 duk__mark_finalize_list(heap); /* mark finalizer work list as reachability roots */
43366 duk__mark_temproots_by_heap_scan(heap); /* temproots */
43367
43368 /*
43369 * Sweep garbage and remove marking flags, and move objects with
43370 * finalizers to the finalizer work list.
43371 *
43372 * Objects to be swept need to get their refcounts finalized before
43373 * they are swept. In other words, their target object refcounts
43374 * need to be decreased. This has to be done before freeing any
43375 * objects to avoid decref'ing dangling pointers (which may happen
43376 * even without bugs, e.g. with reference loops)
43377 *
43378 * Because strings don't point to other heap objects, similar
43379 * finalization is not necessary for strings.
43380 */
43381
43382 /* XXX: more emergency behavior, e.g. find smaller hash sizes etc */
43383
43384#ifdef DUK_USE_REFERENCE_COUNTING
43385 duk__finalize_refcounts(heap);
43386#endif
43387 duk__sweep_heap(heap, flags, &count_keep_obj);
43388#if defined(DUK_USE_STRTAB_CHAIN)
43389 duk__sweep_stringtable_chain(heap, &count_keep_str);
43390#elif defined(DUK_USE_STRTAB_PROBE)
43391 duk__sweep_stringtable_probe(heap, &count_keep_str);
43392#else
43393#error internal error, invalid strtab options
43394#endif
43395#ifdef DUK_USE_REFERENCE_COUNTING
43396 duk__clear_refzero_list_flags(heap);
43397#endif
43398 duk__clear_finalize_list_flags(heap);
43399
43400 /*
43401 * Object compaction (emergency only).
43402 *
43403 * Object compaction is a separate step after sweeping, as there is
43404 * more free memory for it to work with. Also, currently compaction
43405 * may insert new objects into the heap allocated list and the string
43406 * table which we don't want to do during a sweep (the reachability
43407 * flags of such objects would be incorrect). The objects inserted
43408 * are currently:
43409 *
43410 * - a temporary duk_hbuffer for a new properties allocation
43411 * - if array part is abandoned, string keys are interned
43412 *
43413 * The object insertions go to the front of the list, so they do not
43414 * cause an infinite loop (they are not compacted).
43415 */
43416
43417 if ((flags & DUK_MS_FLAG_EMERGENCY) &&
43418 !(flags & DUK_MS_FLAG_NO_OBJECT_COMPACTION)) {
43419 duk__compact_objects(heap);
43420 }
43421
43422 /*
43423 * String table resize check.
43424 *
43425 * Note: this may silently (and safely) fail if GC is caused by an
43426 * allocation call in stringtable resize_hash(). Resize_hash()
43427 * will prevent a recursive call to itself by setting the
43428 * DUK_MS_FLAG_NO_STRINGTABLE_RESIZE in heap->mark_and_sweep_base_flags.
43429 */
43430
43431 /* XXX: stringtable emergency compaction? */
43432
11fdf7f2
TL
43433 /* XXX: remove this feature entirely? it would only matter for
43434 * emergency GC. Disable for lowest memory builds.
43435 */
7c673cae
FG
43436#if defined(DUK_USE_MS_STRINGTABLE_RESIZE)
43437 if (!(flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE)) {
43438 DUK_DD(DUK_DDPRINT("resize stringtable: %p", (void *) heap));
43439 duk_heap_force_strtab_resize(heap);
43440 } else {
43441 DUK_D(DUK_DPRINT("stringtable resize skipped because DUK_MS_FLAG_NO_STRINGTABLE_RESIZE is set"));
43442 }
43443#endif
43444
43445 /*
43446 * Finalize objects in the finalization work list. Finalized
43447 * objects are queued back to heap_allocated with FINALIZED set.
43448 *
43449 * Since finalizers may cause arbitrary side effects, they are
43450 * prevented during string table and object property allocation
43451 * resizing using the DUK_MS_FLAG_NO_FINALIZERS flag in
43452 * heap->mark_and_sweep_base_flags. In this case the objects
43453 * remain in the finalization work list after mark-and-sweep
43454 * exits and they may be finalized on the next pass.
43455 *
43456 * Finalization currently happens inside "MARKANDSWEEP_RUNNING"
43457 * protection (no mark-and-sweep may be triggered by the
43458 * finalizers). As a side effect:
43459 *
43460 * 1) an out-of-memory error inside a finalizer will not
43461 * cause a mark-and-sweep and may cause the finalizer
43462 * to fail unnecessarily
43463 *
43464 * 2) any temporary objects whose refcount decreases to zero
43465 * during finalization will not be put into refzero_list;
43466 * they can only be collected by another mark-and-sweep
43467 *
43468 * This is not optimal, but since the sweep for this phase has
43469 * already happened, this is probably good enough for now.
43470 */
43471
43472#if defined(DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE)
43473 /* Cannot simulate individual finalizers because finalize_list only
43474 * contains objects with actual finalizers. But simulate side effects
43475 * from finalization by doing a bogus function call and resizing the
43476 * stacks.
43477 */
43478 if (flags & DUK_MS_FLAG_NO_FINALIZERS) {
43479 DUK_D(DUK_DPRINT("skip mark-and-sweep torture finalizer, DUK_MS_FLAG_NO_FINALIZERS is set"));
43480 } else if (!(thr->valstack != NULL && thr->callstack != NULL && thr->catchstack != NULL)) {
43481 DUK_D(DUK_DPRINT("skip mark-and-sweep torture finalizer, thread not yet viable"));
43482 } else {
43483 DUK_D(DUK_DPRINT("run mark-and-sweep torture finalizer"));
43484 duk__markandsweep_torture_finalizer(thr);
43485 }
43486#endif /* DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE */
43487
43488 if (flags & DUK_MS_FLAG_NO_FINALIZERS) {
43489 DUK_D(DUK_DPRINT("finalizer run skipped because DUK_MS_FLAG_NO_FINALIZERS is set"));
43490 } else {
11fdf7f2 43491 duk__run_object_finalizers(heap, flags);
7c673cae
FG
43492 }
43493
43494 /*
43495 * Finish
43496 */
43497
43498 DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap);
43499
43500 /*
43501 * Assertions after
43502 */
43503
43504#ifdef DUK_USE_ASSERTIONS
43505 DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap));
43506 DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap));
43507 DUK_ASSERT(heap->mark_and_sweep_recursion_depth == 0);
43508 duk__assert_heaphdr_flags(heap);
43509#ifdef DUK_USE_REFERENCE_COUNTING
43510 /* Note: DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) may be true; a refcount
43511 * finalizer may trigger a mark-and-sweep.
43512 */
43513 duk__assert_valid_refcounts(heap);
43514#endif /* DUK_USE_REFERENCE_COUNTING */
43515#endif /* DUK_USE_ASSERTIONS */
43516
43517 /*
43518 * Reset trigger counter
43519 */
43520
43521#ifdef DUK_USE_VOLUNTARY_GC
43522 tmp = (count_keep_obj + count_keep_str) / 256;
43523 heap->mark_and_sweep_trigger_counter = (duk_int_t) (
43524 (tmp * DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT) +
43525 DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD);
43526 DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, trigger reset to %ld",
43527 (long) count_keep_obj, (long) count_keep_str, (long) heap->mark_and_sweep_trigger_counter));
43528#else
43529 DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, no voluntary trigger",
43530 (long) count_keep_obj, (long) count_keep_str));
43531#endif
43532
43533 return 0; /* OK */
43534}
43535
43536#else /* DUK_USE_MARK_AND_SWEEP */
43537
43538/* no mark-and-sweep gc */
43539
43540#endif /* DUK_USE_MARK_AND_SWEEP */
7c673cae
FG
43541/*
43542 * Memory allocation handling.
43543 */
43544
43545/* include removed: duk_internal.h */
43546
43547/*
43548 * Helpers
43549 *
43550 * The fast path checks are done within a macro to ensure "inlining"
43551 * while the slow path actions use a helper (which won't typically be
43552 * inlined in size optimized builds).
43553 */
43554
43555#if defined(DUK_USE_MARK_AND_SWEEP) && defined(DUK_USE_VOLUNTARY_GC)
43556#define DUK__VOLUNTARY_PERIODIC_GC(heap) do { \
43557 (heap)->mark_and_sweep_trigger_counter--; \
43558 if ((heap)->mark_and_sweep_trigger_counter <= 0) { \
43559 duk__run_voluntary_gc(heap); \
43560 } \
43561 } while (0)
43562
43563DUK_LOCAL void duk__run_voluntary_gc(duk_heap *heap) {
43564 if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
43565 DUK_DD(DUK_DDPRINT("mark-and-sweep in progress -> skip voluntary mark-and-sweep now"));
43566 } else {
43567 duk_small_uint_t flags;
43568 duk_bool_t rc;
43569
43570 DUK_D(DUK_DPRINT("triggering voluntary mark-and-sweep"));
43571 flags = 0;
43572 rc = duk_heap_mark_and_sweep(heap, flags);
43573 DUK_UNREF(rc);
43574 }
43575}
43576#else
43577#define DUK__VOLUNTARY_PERIODIC_GC(heap) /* no voluntary gc */
43578#endif /* DUK_USE_MARK_AND_SWEEP && DUK_USE_VOLUNTARY_GC */
43579
43580/*
43581 * Allocate memory with garbage collection
43582 */
43583
43584#ifdef DUK_USE_MARK_AND_SWEEP
43585DUK_INTERNAL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size) {
43586 void *res;
43587 duk_bool_t rc;
43588 duk_small_int_t i;
43589
43590 DUK_ASSERT(heap != NULL);
43591 DUK_ASSERT_DISABLE(size >= 0);
43592
43593 /*
43594 * Voluntary periodic GC (if enabled)
43595 */
43596
43597 DUK__VOLUNTARY_PERIODIC_GC(heap);
43598
43599 /*
43600 * First attempt
43601 */
43602
43603#ifdef DUK_USE_GC_TORTURE
43604 /* simulate alloc failure on every alloc (except when mark-and-sweep is running) */
43605 if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
43606 DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first alloc attempt fails"));
43607 res = NULL;
43608 DUK_UNREF(res);
43609 goto skip_attempt;
43610 }
43611#endif
43612 res = heap->alloc_func(heap->heap_udata, size);
43613 if (res || size == 0) {
43614 /* for zero size allocations NULL is allowed */
43615 return res;
43616 }
43617#ifdef DUK_USE_GC_TORTURE
43618 skip_attempt:
43619#endif
43620
43621 DUK_D(DUK_DPRINT("first alloc attempt failed, attempt to gc and retry"));
43622
43623 /*
43624 * Avoid a GC if GC is already running. This can happen at a late
43625 * stage in a GC when we try to e.g. resize the stringtable
43626 * or compact objects.
43627 */
43628
43629 if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
43630 DUK_D(DUK_DPRINT("duk_heap_mem_alloc() failed, gc in progress (gc skipped), alloc size %ld", (long) size));
43631 return NULL;
43632 }
43633
43634 /*
43635 * Retry with several GC attempts. Initial attempts are made without
43636 * emergency mode; later attempts use emergency mode which minimizes
43637 * memory allocations forcibly.
43638 */
43639
43640 for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) {
43641 duk_small_uint_t flags;
43642
43643 flags = 0;
43644 if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) {
43645 flags |= DUK_MS_FLAG_EMERGENCY;
43646 }
43647
43648 rc = duk_heap_mark_and_sweep(heap, flags);
43649 DUK_UNREF(rc);
43650
43651 res = heap->alloc_func(heap->heap_udata, size);
43652 if (res) {
43653 DUK_D(DUK_DPRINT("duk_heap_mem_alloc() succeeded after gc (pass %ld), alloc size %ld",
43654 (long) (i + 1), (long) size));
43655 return res;
43656 }
43657 }
43658
43659 DUK_D(DUK_DPRINT("duk_heap_mem_alloc() failed even after gc, alloc size %ld", (long) size));
43660 return NULL;
43661}
43662#else /* DUK_USE_MARK_AND_SWEEP */
43663/*
43664 * Compared to a direct macro expansion this wrapper saves a few
43665 * instructions because no heap dereferencing is required.
43666 */
43667DUK_INTERNAL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size) {
43668 DUK_ASSERT(heap != NULL);
43669 DUK_ASSERT_DISABLE(size >= 0);
43670
43671 return heap->alloc_func(heap->heap_udata, size);
43672}
43673#endif /* DUK_USE_MARK_AND_SWEEP */
43674
43675DUK_INTERNAL void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size) {
43676 void *res;
43677
43678 DUK_ASSERT(heap != NULL);
43679 DUK_ASSERT_DISABLE(size >= 0);
43680
43681 res = DUK_ALLOC(heap, size);
43682 if (res) {
43683 /* assume memset with zero size is OK */
43684 DUK_MEMZERO(res, size);
43685 }
43686 return res;
43687}
43688
43689/*
43690 * Reallocate memory with garbage collection
43691 */
43692
43693#ifdef DUK_USE_MARK_AND_SWEEP
43694DUK_INTERNAL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize) {
43695 void *res;
43696 duk_bool_t rc;
43697 duk_small_int_t i;
43698
43699 DUK_ASSERT(heap != NULL);
43700 /* ptr may be NULL */
43701 DUK_ASSERT_DISABLE(newsize >= 0);
43702
43703 /*
43704 * Voluntary periodic GC (if enabled)
43705 */
43706
43707 DUK__VOLUNTARY_PERIODIC_GC(heap);
43708
43709 /*
43710 * First attempt
43711 */
43712
43713#ifdef DUK_USE_GC_TORTURE
43714 /* simulate alloc failure on every realloc (except when mark-and-sweep is running) */
43715 if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
43716 DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first realloc attempt fails"));
43717 res = NULL;
43718 DUK_UNREF(res);
43719 goto skip_attempt;
43720 }
43721#endif
43722 res = heap->realloc_func(heap->heap_udata, ptr, newsize);
43723 if (res || newsize == 0) {
43724 /* for zero size allocations NULL is allowed */
43725 return res;
43726 }
43727#ifdef DUK_USE_GC_TORTURE
43728 skip_attempt:
43729#endif
43730
43731 DUK_D(DUK_DPRINT("first realloc attempt failed, attempt to gc and retry"));
43732
43733 /*
43734 * Avoid a GC if GC is already running. See duk_heap_mem_alloc().
43735 */
43736
43737 if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
43738 DUK_D(DUK_DPRINT("duk_heap_mem_realloc() failed, gc in progress (gc skipped), alloc size %ld", (long) newsize));
43739 return NULL;
43740 }
43741
43742 /*
43743 * Retry with several GC attempts. Initial attempts are made without
43744 * emergency mode; later attempts use emergency mode which minimizes
43745 * memory allocations forcibly.
43746 */
43747
43748 for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) {
43749 duk_small_uint_t flags;
43750
43751 flags = 0;
43752 if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) {
43753 flags |= DUK_MS_FLAG_EMERGENCY;
43754 }
43755
43756 rc = duk_heap_mark_and_sweep(heap, flags);
43757 DUK_UNREF(rc);
43758
43759 res = heap->realloc_func(heap->heap_udata, ptr, newsize);
43760 if (res || newsize == 0) {
43761 DUK_D(DUK_DPRINT("duk_heap_mem_realloc() succeeded after gc (pass %ld), alloc size %ld",
43762 (long) (i + 1), (long) newsize));
43763 return res;
43764 }
43765 }
43766
43767 DUK_D(DUK_DPRINT("duk_heap_mem_realloc() failed even after gc, alloc size %ld", (long) newsize));
43768 return NULL;
43769}
43770#else /* DUK_USE_MARK_AND_SWEEP */
43771/* saves a few instructions to have this wrapper (see comment on duk_heap_mem_alloc) */
43772DUK_INTERNAL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize) {
43773 DUK_ASSERT(heap != NULL);
43774 /* ptr may be NULL */
43775 DUK_ASSERT_DISABLE(newsize >= 0);
43776
43777 return heap->realloc_func(heap->heap_udata, ptr, newsize);
43778}
43779#endif /* DUK_USE_MARK_AND_SWEEP */
43780
43781/*
43782 * Reallocate memory with garbage collection, using a callback to provide
43783 * the current allocated pointer. This variant is used when a mark-and-sweep
43784 * (e.g. finalizers) might change the original pointer.
43785 */
43786
43787#ifdef DUK_USE_MARK_AND_SWEEP
43788DUK_INTERNAL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize) {
43789 void *res;
43790 duk_bool_t rc;
43791 duk_small_int_t i;
43792
43793 DUK_ASSERT(heap != NULL);
43794 DUK_ASSERT_DISABLE(newsize >= 0);
43795
43796 /*
43797 * Voluntary periodic GC (if enabled)
43798 */
43799
43800 DUK__VOLUNTARY_PERIODIC_GC(heap);
43801
43802 /*
43803 * First attempt
43804 */
43805
43806#ifdef DUK_USE_GC_TORTURE
43807 /* simulate alloc failure on every realloc (except when mark-and-sweep is running) */
43808 if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
43809 DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first indirect realloc attempt fails"));
43810 res = NULL;
43811 DUK_UNREF(res);
43812 goto skip_attempt;
43813 }
43814#endif
43815 res = heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize);
43816 if (res || newsize == 0) {
43817 /* for zero size allocations NULL is allowed */
43818 return res;
43819 }
43820#ifdef DUK_USE_GC_TORTURE
43821 skip_attempt:
43822#endif
43823
43824 DUK_D(DUK_DPRINT("first indirect realloc attempt failed, attempt to gc and retry"));
43825
43826 /*
43827 * Avoid a GC if GC is already running. See duk_heap_mem_alloc().
43828 */
43829
43830 if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
43831 DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() failed, gc in progress (gc skipped), alloc size %ld", (long) newsize));
43832 return NULL;
43833 }
43834
43835 /*
43836 * Retry with several GC attempts. Initial attempts are made without
43837 * emergency mode; later attempts use emergency mode which minimizes
43838 * memory allocations forcibly.
43839 */
43840
43841 for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) {
43842 duk_small_uint_t flags;
43843
43844#ifdef DUK_USE_ASSERTIONS
43845 void *ptr_pre; /* ptr before mark-and-sweep */
43846 void *ptr_post;
43847#endif
43848
43849#ifdef DUK_USE_ASSERTIONS
43850 ptr_pre = cb(heap, ud);
43851#endif
43852 flags = 0;
43853 if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) {
43854 flags |= DUK_MS_FLAG_EMERGENCY;
43855 }
43856
43857 rc = duk_heap_mark_and_sweep(heap, flags);
43858 DUK_UNREF(rc);
43859#ifdef DUK_USE_ASSERTIONS
43860 ptr_post = cb(heap, ud);
43861 if (ptr_pre != ptr_post) {
43862 /* useful for debugging */
43863 DUK_DD(DUK_DDPRINT("note: base pointer changed by mark-and-sweep: %p -> %p",
43864 (void *) ptr_pre, (void *) ptr_post));
43865 }
43866#endif
43867
43868 /* Note: key issue here is to re-lookup the base pointer on every attempt.
43869 * The pointer being reallocated may change after every mark-and-sweep.
43870 */
43871
43872 res = heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize);
43873 if (res || newsize == 0) {
43874 DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() succeeded after gc (pass %ld), alloc size %ld",
43875 (long) (i + 1), (long) newsize));
43876 return res;
43877 }
43878 }
43879
43880 DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() failed even after gc, alloc size %ld", (long) newsize));
43881 return NULL;
43882}
43883#else /* DUK_USE_MARK_AND_SWEEP */
43884/* saves a few instructions to have this wrapper (see comment on duk_heap_mem_alloc) */
43885DUK_INTERNAL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize) {
43886 return heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize);
43887}
43888#endif /* DUK_USE_MARK_AND_SWEEP */
43889
43890/*
43891 * Free memory
43892 */
43893
43894#ifdef DUK_USE_MARK_AND_SWEEP
43895DUK_INTERNAL void duk_heap_mem_free(duk_heap *heap, void *ptr) {
43896 DUK_ASSERT(heap != NULL);
43897 /* ptr may be NULL */
43898
43899 /* Must behave like a no-op with NULL and any pointer returned from
43900 * malloc/realloc with zero size.
43901 */
43902 heap->free_func(heap->heap_udata, ptr);
43903
43904 /* Count free operations toward triggering a GC but never actually trigger
43905 * a GC from a free. Otherwise code which frees internal structures would
43906 * need to put in NULLs at every turn to ensure the object is always in
43907 * consistent state for a mark-and-sweep.
43908 */
43909#ifdef DUK_USE_VOLUNTARY_GC
43910 heap->mark_and_sweep_trigger_counter--;
43911#endif
43912}
43913#else
43914/* saves a few instructions to have this wrapper (see comment on duk_heap_mem_alloc) */
43915DUK_INTERNAL void duk_heap_mem_free(duk_heap *heap, void *ptr) {
43916 DUK_ASSERT(heap != NULL);
43917 /* ptr may be NULL */
43918
43919 /* Note: must behave like a no-op with NULL and any pointer
43920 * returned from malloc/realloc with zero size.
43921 */
43922 heap->free_func(heap->heap_udata, ptr);
43923}
43924#endif
7c673cae
FG
43925/*
43926 * Support functions for duk_heap.
43927 */
43928
43929/* include removed: duk_internal.h */
43930
43931#if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_REFERENCE_COUNTING)
43932/* arbitrary remove only works with double linked heap, and is only required by
43933 * reference counting so far.
43934 */
43935DUK_INTERNAL void duk_heap_remove_any_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) {
43936 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING);
43937
43938 if (DUK_HEAPHDR_GET_PREV(heap, hdr)) {
43939 DUK_HEAPHDR_SET_NEXT(heap, DUK_HEAPHDR_GET_PREV(heap, hdr), DUK_HEAPHDR_GET_NEXT(heap, hdr));
43940 } else {
43941 heap->heap_allocated = DUK_HEAPHDR_GET_NEXT(heap, hdr);
43942 }
43943 if (DUK_HEAPHDR_GET_NEXT(heap, hdr)) {
43944 DUK_HEAPHDR_SET_PREV(heap, DUK_HEAPHDR_GET_NEXT(heap, hdr), DUK_HEAPHDR_GET_PREV(heap, hdr));
43945 } else {
43946 ;
43947 }
11fdf7f2
TL
43948
43949 /* The prev/next pointers of the removed duk_heaphdr are left as garbage.
43950 * It's up to the caller to ensure they're written before inserting the
43951 * object back.
43952 */
7c673cae
FG
43953}
43954#endif
43955
43956DUK_INTERNAL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) {
43957 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING);
43958
43959#ifdef DUK_USE_DOUBLE_LINKED_HEAP
43960 if (heap->heap_allocated) {
43961 DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, heap->heap_allocated) == NULL);
43962 DUK_HEAPHDR_SET_PREV(heap, heap->heap_allocated, hdr);
43963 }
43964 DUK_HEAPHDR_SET_PREV(heap, hdr, NULL);
43965#endif
43966 DUK_HEAPHDR_SET_NEXT(heap, hdr, heap->heap_allocated);
43967 heap->heap_allocated = hdr;
43968}
43969
43970#ifdef DUK_USE_INTERRUPT_COUNTER
43971DUK_INTERNAL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr) {
43972 duk_hthread *curr_thr;
43973
43974 DUK_ASSERT(heap != NULL);
43975
43976 if (new_thr != NULL) {
43977 curr_thr = heap->curr_thread;
43978 if (curr_thr == NULL) {
43979 /* For initial entry use default value; zero forces an
43980 * interrupt before executing the first insturction.
43981 */
43982 DUK_DD(DUK_DDPRINT("switch thread, initial entry, init default interrupt counter"));
43983 new_thr->interrupt_counter = 0;
43984 new_thr->interrupt_init = 0;
43985 } else {
43986 /* Copy interrupt counter/init value state to new thread (if any).
43987 * It's OK for new_thr to be the same as curr_thr.
43988 */
43989#if defined(DUK_USE_DEBUG)
43990 if (new_thr != curr_thr) {
43991 DUK_DD(DUK_DDPRINT("switch thread, not initial entry, copy interrupt counter"));
43992 }
43993#endif
43994 new_thr->interrupt_counter = curr_thr->interrupt_counter;
43995 new_thr->interrupt_init = curr_thr->interrupt_init;
43996 }
43997 } else {
43998 DUK_DD(DUK_DDPRINT("switch thread, new thread is NULL, no interrupt counter changes"));
43999 }
44000
44001 heap->curr_thread = new_thr; /* may be NULL */
44002}
44003#endif /* DUK_USE_INTERRUPT_COUNTER */
7c673cae
FG
44004/*
44005 * Reference counting implementation.
44006 */
44007
44008/* include removed: duk_internal.h */
44009
44010#ifdef DUK_USE_REFERENCE_COUNTING
44011
44012#ifndef DUK_USE_DOUBLE_LINKED_HEAP
44013#error internal error, reference counting requires a double linked heap
44014#endif
44015
44016/*
44017 * Misc
44018 */
44019
44020DUK_LOCAL void duk__queue_refzero(duk_heap *heap, duk_heaphdr *hdr) {
44021 /* tail insert: don't disturb head in case refzero is running */
44022
44023 if (heap->refzero_list != NULL) {
44024 duk_heaphdr *hdr_prev;
44025
44026 hdr_prev = heap->refzero_list_tail;
44027 DUK_ASSERT(hdr_prev != NULL);
44028 DUK_ASSERT(DUK_HEAPHDR_GET_NEXT(heap, hdr_prev) == NULL);
44029
44030 DUK_HEAPHDR_SET_NEXT(heap, hdr, NULL);
44031 DUK_HEAPHDR_SET_PREV(heap, hdr, hdr_prev);
44032 DUK_HEAPHDR_SET_NEXT(heap, hdr_prev, hdr);
11fdf7f2
TL
44033 DUK_ASSERT_HEAPHDR_LINKS(heap, hdr);
44034 DUK_ASSERT_HEAPHDR_LINKS(heap, hdr_prev);
7c673cae
FG
44035 heap->refzero_list_tail = hdr;
44036 } else {
44037 DUK_ASSERT(heap->refzero_list_tail == NULL);
44038 DUK_HEAPHDR_SET_NEXT(heap, hdr, NULL);
44039 DUK_HEAPHDR_SET_PREV(heap, hdr, NULL);
11fdf7f2 44040 DUK_ASSERT_HEAPHDR_LINKS(heap, hdr);
7c673cae
FG
44041 heap->refzero_list = hdr;
44042 heap->refzero_list_tail = hdr;
44043 }
44044}
44045
44046/*
44047 * Heap object refcount finalization.
44048 *
44049 * When an object is about to be freed, all other objects it refers to must
44050 * be decref'd. Refcount finalization does NOT free the object or its inner
44051 * allocations (mark-and-sweep shares these helpers), it just manipulates
44052 * the refcounts.
44053 *
44054 * Note that any of the decref's may cause a refcount to drop to zero, BUT
44055 * it will not be processed inline; instead, because refzero is already
44056 * running, the objects will just be queued to refzero list and processed
44057 * later. This eliminates C recursion.
44058 */
44059
44060DUK_LOCAL void duk__refcount_finalize_hobject(duk_hthread *thr, duk_hobject *h) {
44061 duk_uint_fast32_t i;
44062
44063 DUK_ASSERT(h);
44064 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h) == DUK_HTYPE_OBJECT);
44065
44066 /* XXX: better to get base and walk forwards? */
44067
44068 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) {
44069 duk_hstring *key = DUK_HOBJECT_E_GET_KEY(thr->heap, h, i);
44070 if (!key) {
44071 continue;
44072 }
44073 duk_heaphdr_decref(thr, (duk_heaphdr *) key);
44074 if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, h, i)) {
44075 duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, h, i));
44076 duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, h, i));
44077 } else {
44078 duk_tval_decref(thr, DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, h, i));
44079 }
44080 }
44081
44082 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) {
44083 duk_tval_decref(thr, DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, h, i));
44084 }
44085
44086 /* hash part is a 'weak reference' and does not contribute */
44087
44088 duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h));
44089
44090 if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
44091 duk_hcompiledfunction *f = (duk_hcompiledfunction *) h;
44092 duk_tval *tv, *tv_end;
44093 duk_hobject **funcs, **funcs_end;
44094
11fdf7f2
TL
44095 if (DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, f) != NULL) {
44096 tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, f);
44097 tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, f);
44098 while (tv < tv_end) {
44099 duk_tval_decref(thr, tv);
44100 tv++;
44101 }
7c673cae 44102
11fdf7f2
TL
44103 funcs = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, f);
44104 funcs_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, f);
44105 while (funcs < funcs_end) {
44106 duk_heaphdr_decref(thr, (duk_heaphdr *) *funcs);
44107 funcs++;
44108 }
44109 } else {
44110 /* May happen in some out-of-memory corner cases. */
44111 DUK_D(DUK_DPRINT("duk_hcompiledfunction 'data' is NULL, skipping decref"));
7c673cae
FG
44112 }
44113
44114 duk_heaphdr_decref(thr, (duk_heaphdr *) DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, f));
44115 } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
44116 duk_hnativefunction *f = (duk_hnativefunction *) h;
44117 DUK_UNREF(f);
44118 /* nothing to finalize */
44119 } else if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
44120 duk_hbufferobject *b = (duk_hbufferobject *) h;
44121 if (b->buf) {
44122 duk_heaphdr_decref(thr, (duk_heaphdr *) b->buf);
44123 }
44124 } else if (DUK_HOBJECT_IS_THREAD(h)) {
44125 duk_hthread *t = (duk_hthread *) h;
44126 duk_tval *tv;
44127
44128 tv = t->valstack;
11fdf7f2 44129 while (tv < t->valstack_top) {
7c673cae
FG
44130 duk_tval_decref(thr, tv);
44131 tv++;
44132 }
44133
44134 for (i = 0; i < (duk_uint_fast32_t) t->callstack_top; i++) {
44135 duk_activation *act = t->callstack + i;
44136 duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) DUK_ACT_GET_FUNC(act));
44137 duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) act->var_env);
44138 duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) act->lex_env);
44139#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
44140 duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) act->prev_caller);
44141#endif
44142 }
44143
44144#if 0 /* nothing now */
44145 for (i = 0; i < (duk_uint_fast32_t) t->catchstack_top; i++) {
44146 duk_catcher *cat = t->catchstack + i;
44147 }
44148#endif
44149
44150 for (i = 0; i < DUK_NUM_BUILTINS; i++) {
44151 duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) t->builtins[i]);
44152 }
44153
44154 duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) t->resumer);
44155 }
44156}
44157
44158DUK_INTERNAL void duk_heaphdr_refcount_finalize(duk_hthread *thr, duk_heaphdr *hdr) {
44159 DUK_ASSERT(hdr);
44160
44161 switch ((int) DUK_HEAPHDR_GET_TYPE(hdr)) {
44162 case DUK_HTYPE_OBJECT:
44163 duk__refcount_finalize_hobject(thr, (duk_hobject *) hdr);
44164 break;
44165 case DUK_HTYPE_BUFFER:
44166 /* nothing to finalize */
44167 break;
44168 case DUK_HTYPE_STRING:
44169 /* cannot happen: strings are not put into refzero list (they don't even have the next/prev pointers) */
44170 default:
44171 DUK_UNREACHABLE();
44172 }
44173}
44174
44175#if defined(DUK_USE_REFZERO_FINALIZER_TORTURE)
44176DUK_LOCAL duk_ret_t duk__refcount_fake_finalizer(duk_context *ctx) {
44177 DUK_UNREF(ctx);
44178 DUK_D(DUK_DPRINT("fake refcount torture finalizer executed"));
44179#if 0
44180 DUK_DD(DUK_DDPRINT("fake torture finalizer for: %!T", duk_get_tval(ctx, 0)));
44181#endif
44182 /* Require a lot of stack to force a value stack grow/shrink. */
44183 duk_require_stack(ctx, 100000);
44184
44185 /* XXX: do something to force a callstack grow/shrink, perhaps
44186 * just a manual forced resize?
44187 */
44188 return 0;
44189}
44190
44191DUK_LOCAL void duk__refcount_run_torture_finalizer(duk_hthread *thr, duk_hobject *obj) {
44192 duk_context *ctx;
44193 duk_int_t rc;
44194
44195 DUK_ASSERT(thr != NULL);
44196 DUK_ASSERT(obj != NULL);
44197 ctx = (duk_context *) thr;
44198
44199 /* Avoid fake finalization for the duk__refcount_fake_finalizer function
44200 * itself, otherwise we're in infinite recursion.
44201 */
44202 if (DUK_HOBJECT_HAS_NATIVEFUNCTION(obj)) {
44203 if (((duk_hnativefunction *) obj)->func == duk__refcount_fake_finalizer) {
44204 DUK_DD(DUK_DDPRINT("avoid fake torture finalizer for duk__refcount_fake_finalizer itself"));
44205 return;
44206 }
44207 }
44208 /* Avoid fake finalization when callstack limit has been reached.
44209 * Otherwise a callstack limit error will be created, then refzero'ed,
44210 * and we're in an infinite loop.
44211 */
44212 if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit ||
44213 thr->callstack_size + 2 * DUK_CALLSTACK_GROW_STEP >= thr->callstack_max /*approximate*/) {
44214 DUK_D(DUK_DPRINT("call recursion depth reached, avoid fake torture finalizer"));
44215 return;
44216 }
44217
44218 /* Run fake finalizer. Avoid creating new refzero queue entries
44219 * so that we are not forced into a forever loop.
44220 */
44221 duk_push_c_function(ctx, duk__refcount_fake_finalizer, 1 /*nargs*/);
44222 duk_push_hobject(ctx, obj);
44223 rc = duk_pcall(ctx, 1);
44224 DUK_UNREF(rc); /* ignored */
44225 duk_pop(ctx);
44226}
44227#endif /* DUK_USE_REFZERO_FINALIZER_TORTURE */
44228
44229/*
44230 * Refcount memory freeing loop.
44231 *
44232 * Frees objects in the refzero_pending list until the list becomes
44233 * empty. When an object is freed, its references get decref'd and
44234 * may cause further objects to be queued for freeing.
44235 *
44236 * This could be expanded to allow incremental freeing: just bail out
44237 * early and resume at a future alloc/decref/refzero.
44238 */
44239
44240DUK_LOCAL void duk__refzero_free_pending(duk_hthread *thr) {
44241 duk_heaphdr *h1, *h2;
44242 duk_heap *heap;
44243 duk_int_t count = 0;
44244
44245 DUK_ASSERT(thr != NULL);
44246 DUK_ASSERT(thr->heap != NULL);
44247 heap = thr->heap;
44248 DUK_ASSERT(heap != NULL);
44249
44250 /*
44251 * Detect recursive invocation
44252 */
44253
44254 if (DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap)) {
44255 DUK_DDD(DUK_DDDPRINT("refzero free running, skip run"));
44256 return;
44257 }
44258
44259 /*
44260 * Churn refzero_list until empty
44261 */
44262
44263 DUK_HEAP_SET_REFZERO_FREE_RUNNING(heap);
44264 while (heap->refzero_list) {
44265 duk_hobject *obj;
44266 duk_bool_t rescued = 0;
44267
44268 /*
44269 * Pick an object from the head (don't remove yet).
44270 */
44271
44272 h1 = heap->refzero_list;
44273 obj = (duk_hobject *) h1;
44274 DUK_DD(DUK_DDPRINT("refzero processing %p: %!O", (void *) h1, (duk_heaphdr *) h1));
44275 DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, h1) == NULL);
44276 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(h1) == DUK_HTYPE_OBJECT); /* currently, always the case */
44277
44278#if defined(DUK_USE_REFZERO_FINALIZER_TORTURE)
44279 /* Torture option to shake out finalizer side effect issues:
44280 * make a bogus function call for every finalizable object,
44281 * essentially simulating the case where everything has a
44282 * finalizer.
44283 */
44284 DUK_DD(DUK_DDPRINT("refzero torture enabled, fake finalizer"));
44285 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h1) == 0);
44286 DUK_HEAPHDR_PREINC_REFCOUNT(h1); /* bump refcount to prevent refzero during finalizer processing */
44287 duk__refcount_run_torture_finalizer(thr, obj); /* must never longjmp */
44288 DUK_HEAPHDR_PREDEC_REFCOUNT(h1); /* remove artificial bump */
44289 DUK_ASSERT_DISABLE(h1->h_refcount >= 0); /* refcount is unsigned, so always true */
44290#endif
44291
44292 /*
44293 * Finalizer check.
44294 *
44295 * Note: running a finalizer may have arbitrary side effects, e.g.
44296 * queue more objects on refzero_list (tail), or even trigger a
44297 * mark-and-sweep.
44298 *
44299 * Note: quick reject check should match vast majority of
44300 * objects and must be safe (not throw any errors, ever).
44301 */
44302
11fdf7f2
TL
44303 /* An object may have FINALIZED here if it was finalized by mark-and-sweep
44304 * on a previous run and refcount then decreased to zero. We won't run the
44305 * finalizer again here.
7c673cae
FG
44306 */
44307
44308 /* A finalizer is looked up from the object and up its prototype chain
44309 * (which allows inherited finalizers).
44310 */
44311 if (duk_hobject_hasprop_raw(thr, obj, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) {
44312 DUK_DDD(DUK_DDDPRINT("object has a finalizer, run it"));
44313
44314 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h1) == 0);
44315 DUK_HEAPHDR_PREINC_REFCOUNT(h1); /* bump refcount to prevent refzero during finalizer processing */
44316
44317 duk_hobject_run_finalizer(thr, obj); /* must never longjmp */
11fdf7f2 44318 DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(h1)); /* duk_hobject_run_finalizer() sets */
7c673cae
FG
44319
44320 DUK_HEAPHDR_PREDEC_REFCOUNT(h1); /* remove artificial bump */
44321 DUK_ASSERT_DISABLE(h1->h_refcount >= 0); /* refcount is unsigned, so always true */
44322
44323 if (DUK_HEAPHDR_GET_REFCOUNT(h1) != 0) {
44324 DUK_DDD(DUK_DDDPRINT("-> object refcount after finalization non-zero, object will be rescued"));
44325 rescued = 1;
44326 } else {
44327 DUK_DDD(DUK_DDDPRINT("-> object refcount still zero after finalization, object will be freed"));
44328 }
44329 }
44330
44331 /* Refzero head is still the same. This is the case even if finalizer
44332 * inserted more refzero objects; they are inserted to the tail.
44333 */
44334 DUK_ASSERT(h1 == heap->refzero_list);
44335
44336 /*
44337 * Remove the object from the refzero list. This cannot be done
44338 * before a possible finalizer has been executed; the finalizer
44339 * may trigger a mark-and-sweep, and mark-and-sweep must be able
44340 * to traverse a complete refzero_list.
44341 */
44342
44343 h2 = DUK_HEAPHDR_GET_NEXT(heap, h1);
44344 if (h2) {
44345 DUK_HEAPHDR_SET_PREV(heap, h2, NULL); /* not strictly necessary */
44346 heap->refzero_list = h2;
44347 } else {
44348 heap->refzero_list = NULL;
44349 heap->refzero_list_tail = NULL;
44350 }
44351
44352 /*
44353 * Rescue or free.
44354 */
44355
44356 if (rescued) {
44357 /* yes -> move back to heap allocated */
44358 DUK_DD(DUK_DDPRINT("object rescued during refcount finalization: %p", (void *) h1));
11fdf7f2
TL
44359 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(h1));
44360 DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(h1));
44361 DUK_HEAPHDR_CLEAR_FINALIZED(h1);
44362 h2 = heap->heap_allocated;
7c673cae 44363 DUK_HEAPHDR_SET_PREV(heap, h1, NULL);
11fdf7f2
TL
44364 if (h2) {
44365 DUK_HEAPHDR_SET_PREV(heap, h2, h1);
44366 }
44367 DUK_HEAPHDR_SET_NEXT(heap, h1, h2);
44368 DUK_ASSERT_HEAPHDR_LINKS(heap, h1);
44369 DUK_ASSERT_HEAPHDR_LINKS(heap, h2);
7c673cae
FG
44370 heap->heap_allocated = h1;
44371 } else {
44372 /* no -> decref members, then free */
44373 duk__refcount_finalize_hobject(thr, obj);
44374 duk_heap_free_heaphdr_raw(heap, h1);
44375 }
44376
44377 count++;
44378 }
44379 DUK_HEAP_CLEAR_REFZERO_FREE_RUNNING(heap);
44380
44381 DUK_DDD(DUK_DDDPRINT("refzero processed %ld objects", (long) count));
44382
44383 /*
44384 * Once the whole refzero cascade has been freed, check for
44385 * a voluntary mark-and-sweep.
44386 */
44387
44388#if defined(DUK_USE_MARK_AND_SWEEP) && defined(DUK_USE_VOLUNTARY_GC)
44389 /* 'count' is more or less comparable to normal trigger counter update
44390 * which happens in memory block (re)allocation.
44391 */
44392 heap->mark_and_sweep_trigger_counter -= count;
44393 if (heap->mark_and_sweep_trigger_counter <= 0) {
11fdf7f2
TL
44394 if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
44395 DUK_D(DUK_DPRINT("mark-and-sweep in progress -> skip voluntary mark-and-sweep now"));
44396 } else {
44397 duk_bool_t rc;
44398 duk_small_uint_t flags = 0; /* not emergency */
44399 DUK_D(DUK_DPRINT("refcount triggering mark-and-sweep"));
44400 rc = duk_heap_mark_and_sweep(heap, flags);
44401 DUK_UNREF(rc);
44402 DUK_D(DUK_DPRINT("refcount triggered mark-and-sweep => rc %ld", (long) rc));
44403 }
7c673cae
FG
44404 }
44405#endif /* DUK_USE_MARK_AND_SWEEP && DUK_USE_VOLUNTARY_GC */
44406}
44407
44408/*
44409 * Incref and decref functions.
44410 *
44411 * Decref may trigger immediate refzero handling, which may free and finalize
44412 * an arbitrary number of objects.
44413 *
44414 */
44415
44416DUK_INTERNAL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h) {
44417 duk_heap *heap;
44418
44419 DUK_ASSERT(thr != NULL);
44420 DUK_ASSERT(h != NULL);
44421
44422 heap = thr->heap;
44423 DUK_DDD(DUK_DDDPRINT("refzero %p: %!O", (void *) h, (duk_heaphdr *) h));
44424
7c673cae 44425 /*
11fdf7f2
TL
44426 * Refzero handling is skipped entirely if (1) mark-and-sweep is
44427 * running or (2) execution is paused in the debugger. The objects
44428 * are left in the heap, and will be freed by mark-and-sweep or
44429 * eventual heap destruction.
7c673cae 44430 *
11fdf7f2
TL
44431 * This is necessary during mark-and-sweep because refcounts are also
44432 * updated during the sweep phase (otherwise objects referenced by a
44433 * swept object would have incorrect refcounts) which then calls here.
44434 * This could be avoided by using separate decref macros in
44435 * mark-and-sweep; however, mark-and-sweep also calls finalizers which
44436 * would use the ordinary decref macros anyway and still call this
44437 * function.
44438 *
44439 * This check must be enabled also when mark-and-sweep support has been
44440 * disabled: the flag is also used in heap destruction when running
44441 * finalizers for remaining objects, and the flag prevents objects from
44442 * being moved around in heap linked lists.
7c673cae 44443 */
11fdf7f2
TL
44444
44445 /* XXX: ideally this would be just one flag (maybe a derived one) so
44446 * that a single bit test is sufficient to check the condition.
44447 */
44448#if defined(DUK_USE_DEBUGGER_SUPPORT)
44449 if (DUK_UNLIKELY(DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap) || DUK_HEAP_IS_PAUSED(heap))) {
44450#else
44451 if (DUK_UNLIKELY(DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap))) {
44452#endif
7c673cae
FG
44453 DUK_DDD(DUK_DDDPRINT("refzero handling suppressed when mark-and-sweep running, object: %p", (void *) h));
44454 return;
44455 }
7c673cae
FG
44456
44457 switch ((duk_small_int_t) DUK_HEAPHDR_GET_TYPE(h)) {
44458 case DUK_HTYPE_STRING:
44459 /*
44460 * Strings have no internal references but do have "weak"
44461 * references in the string cache. Also note that strings
44462 * are not on the heap_allocated list like other heap
44463 * elements.
44464 */
44465
44466 duk_heap_strcache_string_remove(heap, (duk_hstring *) h);
44467 duk_heap_string_remove(heap, (duk_hstring *) h);
44468 duk_heap_free_heaphdr_raw(heap, h);
44469 break;
44470
44471 case DUK_HTYPE_OBJECT:
44472 /*
44473 * Objects have internal references. Must finalize through
44474 * the "refzero" work list.
44475 */
44476
44477 duk_heap_remove_any_from_heap_allocated(heap, h);
44478 duk__queue_refzero(heap, h);
44479 duk__refzero_free_pending(thr);
44480 break;
44481
44482 case DUK_HTYPE_BUFFER:
44483 /*
44484 * Buffers have no internal references. However, a dynamic
44485 * buffer has a separate allocation for the buffer. This is
44486 * freed by duk_heap_free_heaphdr_raw().
44487 */
44488
44489 duk_heap_remove_any_from_heap_allocated(heap, h);
44490 duk_heap_free_heaphdr_raw(heap, h);
44491 break;
44492
44493 default:
44494 DUK_D(DUK_DPRINT("invalid heap type in decref: %ld", (long) DUK_HEAPHDR_GET_TYPE(h)));
44495 DUK_UNREACHABLE();
44496 }
44497}
44498
44499#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
44500DUK_INTERNAL void duk_tval_incref(duk_tval *tv) {
44501 DUK_ASSERT(tv != NULL);
44502
11fdf7f2 44503 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) {
7c673cae
FG
44504 duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
44505 DUK_ASSERT(h != NULL);
44506 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
44507 DUK_ASSERT_DISABLE(h->h_refcount >= 0);
44508 DUK_HEAPHDR_PREINC_REFCOUNT(h);
44509 }
44510}
44511#endif
44512
44513#if 0 /* unused */
44514DUK_INTERNAL void duk_tval_incref_allownull(duk_tval *tv) {
44515 if (tv == NULL) {
44516 return;
44517 }
11fdf7f2 44518 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) {
7c673cae
FG
44519 duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
44520 DUK_ASSERT(h != NULL);
44521 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
44522 DUK_ASSERT_DISABLE(h->h_refcount >= 0);
44523 DUK_HEAPHDR_PREINC_REFCOUNT(h);
44524 }
44525}
44526#endif
44527
44528DUK_INTERNAL void duk_tval_decref(duk_hthread *thr, duk_tval *tv) {
44529 DUK_ASSERT(thr != NULL);
44530 DUK_ASSERT(tv != NULL);
44531
11fdf7f2 44532 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) {
7c673cae
FG
44533 duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
44534 DUK_ASSERT(h != NULL);
44535 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
44536 duk_heaphdr_decref(thr, h);
44537 }
44538}
44539
44540#if 0 /* unused */
44541DUK_INTERNAL void duk_tval_decref_allownull(duk_hthread *thr, duk_tval *tv) {
44542 DUK_ASSERT(thr != NULL);
44543
44544 if (tv == NULL) {
44545 return;
44546 }
11fdf7f2 44547 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) {
7c673cae
FG
44548 duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
44549 DUK_ASSERT(h != NULL);
44550 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
44551 duk_heaphdr_decref(thr, h);
44552 }
44553}
44554#endif
44555
44556#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
44557DUK_INTERNAL void duk_heaphdr_incref(duk_heaphdr *h) {
44558 DUK_ASSERT(h != NULL);
44559 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
44560 DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(h) >= 0);
44561
11fdf7f2
TL
44562#if defined(DUK_USE_ROM_OBJECTS)
44563 if (DUK_HEAPHDR_HAS_READONLY(h)) {
44564 return;
44565 }
44566#endif
44567
7c673cae
FG
44568 DUK_HEAPHDR_PREINC_REFCOUNT(h);
44569}
44570#endif
44571
44572#if 0 /* unused */
44573DUK_INTERNAL void duk_heaphdr_incref_allownull(duk_heaphdr *h) {
44574 if (h == NULL) {
44575 return;
44576 }
44577 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
44578 DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(h) >= 0);
44579
44580 DUK_HEAPHDR_PREINC_REFCOUNT(h);
44581}
44582#endif
44583
44584DUK_INTERNAL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h) {
44585 DUK_ASSERT(thr != NULL);
44586 DUK_ASSERT(thr->heap != NULL);
44587 DUK_ASSERT(h != NULL);
44588 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
44589 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) >= 1);
44590
11fdf7f2
TL
44591#if defined(DUK_USE_ROM_OBJECTS)
44592 if (DUK_HEAPHDR_HAS_READONLY(h)) {
44593 return;
44594 }
44595#endif
7c673cae
FG
44596 if (DUK_HEAPHDR_PREDEC_REFCOUNT(h) != 0) {
44597 return;
44598 }
44599 duk_heaphdr_refzero(thr, h);
44600}
44601
44602DUK_INTERNAL void duk_heaphdr_decref_allownull(duk_hthread *thr, duk_heaphdr *h) {
44603 DUK_ASSERT(thr != NULL);
44604 DUK_ASSERT(thr->heap != NULL);
44605
44606 if (h == NULL) {
44607 return;
44608 }
7c673cae 44609 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
7c673cae 44610
11fdf7f2
TL
44611#if defined(DUK_USE_ROM_OBJECTS)
44612 if (DUK_HEAPHDR_HAS_READONLY(h)) {
44613 return;
44614 }
44615#endif
44616 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) >= 1);
7c673cae
FG
44617 if (DUK_HEAPHDR_PREDEC_REFCOUNT(h) != 0) {
44618 return;
44619 }
44620 duk_heaphdr_refzero(thr, h);
44621}
44622
44623#else
44624
44625/* no refcounting */
44626
44627#endif /* DUK_USE_REFERENCE_COUNTING */
7c673cae
FG
44628/*
44629 * String cache.
44630 *
44631 * Provides a cache to optimize indexed string lookups. The cache keeps
44632 * track of (byte offset, char offset) states for a fixed number of strings.
44633 * Otherwise we'd need to scan from either end of the string, as we store
44634 * strings in (extended) UTF-8.
44635 */
44636
44637/* include removed: duk_internal.h */
44638
44639/*
44640 * Delete references to given hstring from the heap string cache.
44641 *
44642 * String cache references are 'weak': they are not counted towards
44643 * reference counts, nor serve as roots for mark-and-sweep. When an
44644 * object is about to be freed, such references need to be removed.
44645 */
44646
44647DUK_INTERNAL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h) {
44648 duk_small_int_t i;
44649 for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
44650 duk_strcache *c = heap->strcache + i;
44651 if (c->h == h) {
44652 DUK_DD(DUK_DDPRINT("deleting weak strcache reference to hstring %p from heap %p",
44653 (void *) h, (void *) heap));
44654 c->h = NULL;
44655
44656 /* XXX: the string shouldn't appear twice, but we now loop to the
44657 * end anyway; if fixed, add a looping assertion to ensure there
44658 * is no duplicate.
44659 */
44660 }
44661 }
44662}
44663
44664/*
44665 * String scanning helpers
11fdf7f2
TL
44666 *
44667 * All bytes other than UTF-8 continuation bytes ([0x80,0xbf]) are
44668 * considered to contribute a character. This must match how string
44669 * character length is computed.
7c673cae
FG
44670 */
44671
11fdf7f2 44672DUK_LOCAL const duk_uint8_t *duk__scan_forwards(const duk_uint8_t *p, const duk_uint8_t *q, duk_uint_fast32_t n) {
7c673cae
FG
44673 while (n > 0) {
44674 for (;;) {
44675 p++;
44676 if (p >= q) {
44677 return NULL;
44678 }
44679 if ((*p & 0xc0) != 0x80) {
44680 break;
44681 }
44682 }
44683 n--;
44684 }
44685 return p;
44686}
44687
11fdf7f2 44688DUK_LOCAL const duk_uint8_t *duk__scan_backwards(const duk_uint8_t *p, const duk_uint8_t *q, duk_uint_fast32_t n) {
7c673cae
FG
44689 while (n > 0) {
44690 for (;;) {
44691 p--;
44692 if (p < q) {
44693 return NULL;
44694 }
44695 if ((*p & 0xc0) != 0x80) {
44696 break;
44697 }
44698 }
44699 n--;
44700 }
44701 return p;
44702}
44703
44704/*
44705 * Convert char offset to byte offset
44706 *
44707 * Avoid using the string cache if possible: for ASCII strings byte and
44708 * char offsets are equal and for short strings direct scanning may be
44709 * better than using the string cache (which may evict a more important
44710 * entry).
44711 *
44712 * Typing now assumes 32-bit string byte/char offsets (duk_uint_fast32_t).
44713 * Better typing might be to use duk_size_t.
44714 */
44715
44716DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset) {
44717 duk_heap *heap;
44718 duk_strcache *sce;
44719 duk_uint_fast32_t byte_offset;
44720 duk_small_int_t i;
44721 duk_bool_t use_cache;
44722 duk_uint_fast32_t dist_start, dist_end, dist_sce;
11fdf7f2
TL
44723 const duk_uint8_t *p_start;
44724 const duk_uint8_t *p_end;
44725 const duk_uint8_t *p_found;
7c673cae
FG
44726
44727 if (char_offset > DUK_HSTRING_GET_CHARLEN(h)) {
44728 goto error;
44729 }
44730
44731 /*
44732 * For ASCII strings, the answer is simple.
44733 */
44734
44735 if (DUK_HSTRING_IS_ASCII(h)) {
44736 /* clen == blen -> pure ascii */
44737 return char_offset;
44738 }
44739
44740 /*
44741 * For non-ASCII strings, we need to scan forwards or backwards
44742 * from some starting point. The starting point may be the start
44743 * or end of the string, or some cached midpoint in the string
44744 * cache.
44745 *
44746 * For "short" strings we simply scan without checking or updating
44747 * the cache. For longer strings we check and update the cache as
44748 * necessary, inserting a new cache entry if none exists.
44749 */
44750
44751 DUK_DDD(DUK_DDDPRINT("non-ascii string %p, char_offset=%ld, clen=%ld, blen=%ld",
44752 (void *) h, (long) char_offset,
44753 (long) DUK_HSTRING_GET_CHARLEN(h),
44754 (long) DUK_HSTRING_GET_BYTELEN(h)));
44755
44756 heap = thr->heap;
44757 sce = NULL;
44758 use_cache = (DUK_HSTRING_GET_CHARLEN(h) > DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT);
44759
44760 if (use_cache) {
44761#ifdef DUK_USE_DDDPRINT
44762 DUK_DDD(DUK_DDDPRINT("stringcache before char2byte (using cache):"));
44763 for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
44764 duk_strcache *c = heap->strcache + i;
44765 DUK_DDD(DUK_DDDPRINT(" [%ld] -> h=%p, cidx=%ld, bidx=%ld",
44766 (long) i, (void *) c->h, (long) c->cidx, (long) c->bidx));
44767 }
44768#endif
44769
44770 for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
44771 duk_strcache *c = heap->strcache + i;
44772
44773 if (c->h == h) {
44774 sce = c;
44775 break;
44776 }
44777 }
44778 }
44779
44780 /*
44781 * Scan from shortest distance:
44782 * - start of string
44783 * - end of string
44784 * - cache entry (if exists)
44785 */
44786
44787 DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h) >= char_offset);
44788 dist_start = char_offset;
44789 dist_end = DUK_HSTRING_GET_CHARLEN(h) - char_offset;
44790 dist_sce = 0; DUK_UNREF(dist_sce); /* initialize for debug prints, needed if sce==NULL */
44791
11fdf7f2
TL
44792 p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
44793 p_end = (const duk_uint8_t *) (p_start + DUK_HSTRING_GET_BYTELEN(h));
7c673cae
FG
44794 p_found = NULL;
44795
44796 if (sce) {
44797 if (char_offset >= sce->cidx) {
44798 dist_sce = char_offset - sce->cidx;
44799 if ((dist_sce <= dist_start) && (dist_sce <= dist_end)) {
44800 DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
44801 "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
44802 "scan forwards from sce",
44803 (long) use_cache, (void *) (sce ? sce->h : NULL),
44804 (sce ? (long) sce->cidx : (long) -1),
44805 (sce ? (long) sce->bidx : (long) -1),
44806 (long) dist_start, (long) dist_end, (long) dist_sce));
44807
44808 p_found = duk__scan_forwards(p_start + sce->bidx,
44809 p_end,
44810 dist_sce);
44811 goto scan_done;
44812 }
44813 } else {
44814 dist_sce = sce->cidx - char_offset;
44815 if ((dist_sce <= dist_start) && (dist_sce <= dist_end)) {
44816 DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
44817 "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
44818 "scan backwards from sce",
44819 (long) use_cache, (void *) (sce ? sce->h : NULL),
44820 (sce ? (long) sce->cidx : (long) -1),
44821 (sce ? (long) sce->bidx : (long) -1),
44822 (long) dist_start, (long) dist_end, (long) dist_sce));
44823
44824 p_found = duk__scan_backwards(p_start + sce->bidx,
44825 p_start,
44826 dist_sce);
44827 goto scan_done;
44828 }
44829 }
44830 }
44831
44832 /* no sce, or sce scan not best */
44833
44834 if (dist_start <= dist_end) {
44835 DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
44836 "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
44837 "scan forwards from string start",
44838 (long) use_cache, (void *) (sce ? sce->h : NULL),
44839 (sce ? (long) sce->cidx : (long) -1),
44840 (sce ? (long) sce->bidx : (long) -1),
44841 (long) dist_start, (long) dist_end, (long) dist_sce));
44842
44843 p_found = duk__scan_forwards(p_start,
44844 p_end,
44845 dist_start);
44846 } else {
44847 DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
44848 "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
44849 "scan backwards from string end",
44850 (long) use_cache, (void *) (sce ? sce->h : NULL),
44851 (sce ? (long) sce->cidx : (long) -1),
44852 (sce ? (long) sce->bidx : (long) -1),
44853 (long) dist_start, (long) dist_end, (long) dist_sce));
44854
44855 p_found = duk__scan_backwards(p_end,
44856 p_start,
44857 dist_end);
44858 }
44859
44860 scan_done:
44861
44862 if (!p_found) {
44863 /* Scan error: this shouldn't normally happen; it could happen if
44864 * string is not valid UTF-8 data, and clen/blen are not consistent
44865 * with the scanning algorithm.
44866 */
44867 goto error;
44868 }
44869
44870 DUK_ASSERT(p_found >= p_start);
44871 DUK_ASSERT(p_found <= p_end); /* may be equal */
44872 byte_offset = (duk_uint32_t) (p_found - p_start);
44873
44874 DUK_DDD(DUK_DDDPRINT("-> string %p, cidx %ld -> bidx %ld",
44875 (void *) h, (long) char_offset, (long) byte_offset));
44876
44877 /*
44878 * Update cache entry (allocating if necessary), and move the
44879 * cache entry to the first place (in an "LRU" policy).
44880 */
44881
44882 if (use_cache) {
44883 /* update entry, allocating if necessary */
44884 if (!sce) {
44885 sce = heap->strcache + DUK_HEAP_STRCACHE_SIZE - 1; /* take last entry */
44886 sce->h = h;
44887 }
44888 DUK_ASSERT(sce != NULL);
44889 sce->bidx = (duk_uint32_t) (p_found - p_start);
44890 sce->cidx = (duk_uint32_t) char_offset;
44891
44892 /* LRU: move our entry to first */
44893 if (sce > &heap->strcache[0]) {
44894 /*
44895 * A C
44896 * B A
44897 * C <- sce ==> B
44898 * D D
44899 */
44900 duk_strcache tmp;
44901
44902 tmp = *sce;
44903 DUK_MEMMOVE((void *) (&heap->strcache[1]),
11fdf7f2 44904 (const void *) (&heap->strcache[0]),
7c673cae
FG
44905 (size_t) (((char *) sce) - ((char *) &heap->strcache[0])));
44906 heap->strcache[0] = tmp;
44907
44908 /* 'sce' points to the wrong entry here, but is no longer used */
44909 }
44910#ifdef DUK_USE_DDDPRINT
44911 DUK_DDD(DUK_DDDPRINT("stringcache after char2byte (using cache):"));
44912 for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
44913 duk_strcache *c = heap->strcache + i;
44914 DUK_DDD(DUK_DDDPRINT(" [%ld] -> h=%p, cidx=%ld, bidx=%ld",
44915 (long) i, (void *) c->h, (long) c->cidx, (long) c->bidx));
44916 }
44917#endif
44918 }
44919
44920 return byte_offset;
44921
44922 error:
11fdf7f2 44923 DUK_ERROR_INTERNAL_DEFMSG(thr);
7c673cae
FG
44924 return 0;
44925}
7c673cae
FG
44926/*
44927 * Heap stringtable handling, string interning.
44928 */
44929
44930/* include removed: duk_internal.h */
44931
44932#if defined(DUK_USE_STRTAB_PROBE)
44933#define DUK__HASH_INITIAL(hash,h_size) DUK_STRTAB_HASH_INITIAL((hash),(h_size))
44934#define DUK__HASH_PROBE_STEP(hash) DUK_STRTAB_HASH_PROBE_STEP((hash))
44935#define DUK__DELETED_MARKER(heap) DUK_STRTAB_DELETED_MARKER((heap))
44936#endif
44937
11fdf7f2
TL
44938#if defined(DUK_USE_MARK_AND_SWEEP)
44939#define DUK__PREVENT_MS_SIDE_EFFECTS(heap) do { \
44940 (heap)->mark_and_sweep_base_flags |= \
44941 DUK_MS_FLAG_NO_STRINGTABLE_RESIZE | /* avoid recursive string table call */ \
44942 DUK_MS_FLAG_NO_FINALIZERS | /* avoid pressure to add/remove strings, invalidation of call data argument, etc. */ \
44943 DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid array abandoning which interns strings */ \
44944 } while (0)
44945#endif
44946
7c673cae
FG
44947/*
44948 * Create a hstring and insert into the heap. The created object
44949 * is directly garbage collectable with reference count zero.
44950 *
44951 * The caller must place the interned string into the stringtable
44952 * immediately (without chance of a longjmp); otherwise the string
44953 * is lost.
44954 */
44955
44956DUK_LOCAL
44957duk_hstring *duk__alloc_init_hstring(duk_heap *heap,
44958 const duk_uint8_t *str,
44959 duk_uint32_t blen,
44960 duk_uint32_t strhash,
44961 const duk_uint8_t *extdata) {
44962 duk_hstring *res = NULL;
44963 duk_uint8_t *data;
44964 duk_size_t alloc_size;
44965 duk_uarridx_t dummy;
44966 duk_uint32_t clen;
44967
44968#if defined(DUK_USE_STRLEN16)
44969 /* If blen <= 0xffffUL, clen is also guaranteed to be <= 0xffffUL. */
44970 if (blen > 0xffffUL) {
44971 DUK_D(DUK_DPRINT("16-bit string blen/clen active and blen over 16 bits, reject intern"));
44972 return NULL;
44973 }
44974#endif
44975
44976 if (extdata) {
44977 alloc_size = (duk_size_t) sizeof(duk_hstring_external);
44978 res = (duk_hstring *) DUK_ALLOC(heap, alloc_size);
44979 if (!res) {
44980 goto alloc_error;
44981 }
44982 DUK_MEMZERO(res, sizeof(duk_hstring_external));
11fdf7f2 44983#if defined(DUK_USE_EXPLICIT_NULL_INIT)
7c673cae
FG
44984 DUK_HEAPHDR_STRING_INIT_NULLS(&res->hdr);
44985#endif
44986 DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, DUK_HSTRING_FLAG_EXTDATA);
44987
44988 ((duk_hstring_external *) res)->extdata = extdata;
44989 } else {
44990 /* NUL terminate for convenient C access */
44991 alloc_size = (duk_size_t) (sizeof(duk_hstring) + blen + 1);
44992 res = (duk_hstring *) DUK_ALLOC(heap, alloc_size);
44993 if (!res) {
44994 goto alloc_error;
44995 }
44996 DUK_MEMZERO(res, sizeof(duk_hstring));
11fdf7f2 44997#if defined(DUK_USE_EXPLICIT_NULL_INIT)
7c673cae
FG
44998 DUK_HEAPHDR_STRING_INIT_NULLS(&res->hdr);
44999#endif
45000 DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, 0);
45001
45002 data = (duk_uint8_t *) (res + 1);
45003 DUK_MEMCPY(data, str, blen);
45004 data[blen] = (duk_uint8_t) 0;
45005 }
45006
11fdf7f2 45007 DUK_ASSERT(!DUK_HSTRING_HAS_ARRIDX(res));
7c673cae
FG
45008 if (duk_js_to_arrayindex_raw_string(str, blen, &dummy)) {
45009 DUK_HSTRING_SET_ARRIDX(res);
45010 }
45011
45012 /* All strings beginning with 0xff are treated as "internal",
45013 * even strings interned by the user. This allows user code to
45014 * create internal properties too, and makes behavior consistent
45015 * in case user code happens to use a string also used by Duktape
45016 * (such as string has already been interned and has the 'internal'
45017 * flag set).
45018 */
11fdf7f2 45019 DUK_ASSERT(!DUK_HSTRING_HAS_INTERNAL(res));
7c673cae
FG
45020 if (blen > 0 && str[0] == (duk_uint8_t) 0xff) {
45021 DUK_HSTRING_SET_INTERNAL(res);
45022 }
45023
45024 DUK_HSTRING_SET_HASH(res, strhash);
45025 DUK_HSTRING_SET_BYTELEN(res, blen);
11fdf7f2 45026
7c673cae
FG
45027 clen = (duk_uint32_t) duk_unicode_unvalidated_utf8_length(str, (duk_size_t) blen);
45028 DUK_ASSERT(clen <= blen);
11fdf7f2 45029#if defined(DUK_USE_HSTRING_CLEN)
7c673cae 45030 DUK_HSTRING_SET_CHARLEN(res, clen);
11fdf7f2
TL
45031#endif
45032
45033 /* Using an explicit 'ASCII' flag has larger footprint (one call site
45034 * only) but is quite useful for the case when there's no explicit
45035 * 'clen' in duk_hstring.
45036 */
45037 DUK_ASSERT(!DUK_HSTRING_HAS_ASCII(res));
45038 if (clen == blen) {
45039 DUK_HSTRING_SET_ASCII(res);
45040 }
7c673cae
FG
45041
45042 DUK_DDD(DUK_DDDPRINT("interned string, hash=0x%08lx, blen=%ld, clen=%ld, has_arridx=%ld, has_extdata=%ld",
45043 (unsigned long) DUK_HSTRING_GET_HASH(res),
45044 (long) DUK_HSTRING_GET_BYTELEN(res),
45045 (long) DUK_HSTRING_GET_CHARLEN(res),
11fdf7f2
TL
45046 (long) (DUK_HSTRING_HAS_ARRIDX(res) ? 1 : 0),
45047 (long) (DUK_HSTRING_HAS_EXTDATA(res) ? 1 : 0)));
7c673cae
FG
45048
45049 return res;
45050
45051 alloc_error:
45052 DUK_FREE(heap, res);
45053 return NULL;
45054}
45055
45056/*
45057 * String table algorithm: fixed size string table with array chaining
45058 *
45059 * The top level string table has a fixed size, with each slot holding
45060 * either NULL, string pointer, or pointer to a separately allocated
45061 * string pointer list.
45062 *
45063 * This is good for low memory environments using a pool allocator: the
45064 * top level allocation has a fixed size and the pointer lists have quite
45065 * small allocation size, which further matches the typical pool sizes
45066 * needed by objects, strings, property tables, etc.
45067 */
45068
45069#if defined(DUK_USE_STRTAB_CHAIN)
45070
45071#if defined(DUK_USE_HEAPPTR16)
45072DUK_LOCAL duk_bool_t duk__insert_hstring_chain(duk_heap *heap, duk_hstring *h) {
45073 duk_small_uint_t slotidx;
45074 duk_strtab_entry *e;
45075 duk_uint16_t *lst;
45076 duk_uint16_t *new_lst;
45077 duk_size_t i, n;
45078 duk_uint16_t null16 = heap->heapptr_null16;
45079 duk_uint16_t h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
45080
45081 DUK_ASSERT(heap != NULL);
45082 DUK_ASSERT(h != NULL);
45083
45084 slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE;
45085 DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
45086
45087 e = heap->strtable + slotidx;
45088 if (e->listlen == 0) {
45089 if (e->u.str16 == null16) {
45090 e->u.str16 = h16;
45091 } else {
45092 /* Now two entries in the same slot, alloc list */
45093 lst = (duk_uint16_t *) DUK_ALLOC(heap, sizeof(duk_uint16_t) * 2);
45094 if (lst == NULL) {
45095 return 1; /* fail */
45096 }
45097 lst[0] = e->u.str16;
45098 lst[1] = h16;
45099 e->u.strlist16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) lst);
45100 e->listlen = 2;
45101 }
45102 } else {
45103 DUK_ASSERT(e->u.strlist16 != null16);
45104 lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
45105 DUK_ASSERT(lst != NULL);
45106 for (i = 0, n = e->listlen; i < n; i++) {
45107 if (lst[i] == null16) {
45108 lst[i] = h16;
45109 return 0;
45110 }
45111 }
45112
45113 if (e->listlen + 1 == 0) {
45114 /* Overflow, relevant mainly when listlen is 16 bits. */
45115 return 1; /* fail */
45116 }
45117
45118 new_lst = (duk_uint16_t *) DUK_REALLOC(heap, lst, sizeof(duk_uint16_t) * (e->listlen + 1));
45119 if (new_lst == NULL) {
45120 return 1; /* fail */
45121 }
45122 new_lst[e->listlen++] = h16;
45123 e->u.strlist16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) new_lst);
45124 }
45125 return 0;
45126}
45127#else /* DUK_USE_HEAPPTR16 */
45128DUK_LOCAL duk_bool_t duk__insert_hstring_chain(duk_heap *heap, duk_hstring *h) {
45129 duk_small_uint_t slotidx;
45130 duk_strtab_entry *e;
45131 duk_hstring **lst;
45132 duk_hstring **new_lst;
45133 duk_size_t i, n;
45134
45135 DUK_ASSERT(heap != NULL);
45136 DUK_ASSERT(h != NULL);
45137
45138 slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE;
45139 DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
45140
45141 e = heap->strtable + slotidx;
45142 if (e->listlen == 0) {
45143 if (e->u.str == NULL) {
45144 e->u.str = h;
45145 } else {
45146 /* Now two entries in the same slot, alloc list */
45147 lst = (duk_hstring **) DUK_ALLOC(heap, sizeof(duk_hstring *) * 2);
45148 if (lst == NULL) {
45149 return 1; /* fail */
45150 }
45151 lst[0] = e->u.str;
45152 lst[1] = h;
45153 e->u.strlist = lst;
45154 e->listlen = 2;
45155 }
45156 } else {
45157 DUK_ASSERT(e->u.strlist != NULL);
45158 lst = e->u.strlist;
45159 for (i = 0, n = e->listlen; i < n; i++) {
45160 if (lst[i] == NULL) {
45161 lst[i] = h;
45162 return 0;
45163 }
45164 }
45165
45166 if (e->listlen + 1 == 0) {
45167 /* Overflow, relevant mainly when listlen is 16 bits. */
45168 return 1; /* fail */
45169 }
45170
45171 new_lst = (duk_hstring **) DUK_REALLOC(heap, e->u.strlist, sizeof(duk_hstring *) * (e->listlen + 1));
45172 if (new_lst == NULL) {
45173 return 1; /* fail */
45174 }
45175 new_lst[e->listlen++] = h;
45176 e->u.strlist = new_lst;
45177 }
45178 return 0;
45179}
45180#endif /* DUK_USE_HEAPPTR16 */
45181
45182#if defined(DUK_USE_HEAPPTR16)
45183DUK_LOCAL duk_hstring *duk__find_matching_string_chain(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) {
45184 duk_small_uint_t slotidx;
45185 duk_strtab_entry *e;
45186 duk_uint16_t *lst;
45187 duk_size_t i, n;
45188 duk_uint16_t null16 = heap->heapptr_null16;
45189
45190 DUK_ASSERT(heap != NULL);
45191
45192 slotidx = strhash % DUK_STRTAB_CHAIN_SIZE;
45193 DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
45194
45195 e = heap->strtable + slotidx;
45196 if (e->listlen == 0) {
45197 if (e->u.str16 != null16) {
45198 duk_hstring *h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16);
45199 DUK_ASSERT(h != NULL);
45200 if (DUK_HSTRING_GET_BYTELEN(h) == blen &&
11fdf7f2 45201 DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) {
7c673cae
FG
45202 return h;
45203 }
45204 }
45205 } else {
45206 DUK_ASSERT(e->u.strlist16 != null16);
45207 lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
45208 DUK_ASSERT(lst != NULL);
45209 for (i = 0, n = e->listlen; i < n; i++) {
45210 if (lst[i] != null16) {
45211 duk_hstring *h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[i]);
45212 DUK_ASSERT(h != NULL);
45213 if (DUK_HSTRING_GET_BYTELEN(h) == blen &&
11fdf7f2 45214 DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) {
7c673cae
FG
45215 return h;
45216 }
45217 }
45218 }
45219 }
45220
45221 return NULL;
45222}
45223#else /* DUK_USE_HEAPPTR16 */
45224DUK_LOCAL duk_hstring *duk__find_matching_string_chain(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) {
45225 duk_small_uint_t slotidx;
45226 duk_strtab_entry *e;
45227 duk_hstring **lst;
45228 duk_size_t i, n;
45229
45230 DUK_ASSERT(heap != NULL);
45231
45232 slotidx = strhash % DUK_STRTAB_CHAIN_SIZE;
45233 DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
45234
45235 e = heap->strtable + slotidx;
45236 if (e->listlen == 0) {
45237 if (e->u.str != NULL &&
45238 DUK_HSTRING_GET_BYTELEN(e->u.str) == blen &&
11fdf7f2 45239 DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(e->u.str), (size_t) blen) == 0) {
7c673cae
FG
45240 return e->u.str;
45241 }
45242 } else {
45243 DUK_ASSERT(e->u.strlist != NULL);
45244 lst = e->u.strlist;
45245 for (i = 0, n = e->listlen; i < n; i++) {
45246 if (lst[i] != NULL &&
45247 DUK_HSTRING_GET_BYTELEN(lst[i]) == blen &&
11fdf7f2 45248 DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(lst[i]), (size_t) blen) == 0) {
7c673cae
FG
45249 return lst[i];
45250 }
45251 }
45252 }
45253
45254 return NULL;
45255}
45256#endif /* DUK_USE_HEAPPTR16 */
45257
45258#if defined(DUK_USE_HEAPPTR16)
45259DUK_LOCAL void duk__remove_matching_hstring_chain(duk_heap *heap, duk_hstring *h) {
45260 duk_small_uint_t slotidx;
45261 duk_strtab_entry *e;
45262 duk_uint16_t *lst;
45263 duk_size_t i, n;
45264 duk_uint16_t h16;
45265 duk_uint16_t null16 = heap->heapptr_null16;
45266
45267 DUK_ASSERT(heap != NULL);
45268 DUK_ASSERT(h != NULL);
45269
45270 slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE;
45271 DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
45272
45273 DUK_ASSERT(h != NULL);
45274 h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
45275
45276 e = heap->strtable + slotidx;
45277 if (e->listlen == 0) {
45278 if (e->u.str16 == h16) {
45279 e->u.str16 = null16;
45280 return;
45281 }
45282 } else {
45283 DUK_ASSERT(e->u.strlist16 != null16);
45284 lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
45285 DUK_ASSERT(lst != NULL);
45286 for (i = 0, n = e->listlen; i < n; i++) {
45287 if (lst[i] == h16) {
45288 lst[i] = null16;
45289 return;
45290 }
45291 }
45292 }
45293
45294 DUK_D(DUK_DPRINT("failed to find string that should be in stringtable"));
45295 DUK_UNREACHABLE();
45296 return;
45297}
45298#else /* DUK_USE_HEAPPTR16 */
45299DUK_LOCAL void duk__remove_matching_hstring_chain(duk_heap *heap, duk_hstring *h) {
45300 duk_small_uint_t slotidx;
45301 duk_strtab_entry *e;
45302 duk_hstring **lst;
45303 duk_size_t i, n;
45304
45305 DUK_ASSERT(heap != NULL);
45306 DUK_ASSERT(h != NULL);
45307
45308 slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE;
45309 DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
45310
45311 e = heap->strtable + slotidx;
45312 if (e->listlen == 0) {
45313 DUK_ASSERT(h != NULL);
45314 if (e->u.str == h) {
45315 e->u.str = NULL;
45316 return;
45317 }
45318 } else {
45319 DUK_ASSERT(e->u.strlist != NULL);
45320 lst = e->u.strlist;
45321 for (i = 0, n = e->listlen; i < n; i++) {
45322 DUK_ASSERT(h != NULL);
45323 if (lst[i] == h) {
45324 lst[i] = NULL;
45325 return;
45326 }
45327 }
45328 }
45329
45330 DUK_D(DUK_DPRINT("failed to find string that should be in stringtable"));
45331 DUK_UNREACHABLE();
45332 return;
45333}
45334#endif /* DUK_USE_HEAPPTR16 */
45335
45336#if defined(DUK_USE_DEBUG)
45337DUK_INTERNAL void duk_heap_dump_strtab(duk_heap *heap) {
45338 duk_strtab_entry *e;
45339 duk_small_uint_t i;
45340 duk_size_t j, n, used;
45341#if defined(DUK_USE_HEAPPTR16)
45342 duk_uint16_t *lst;
45343 duk_uint16_t null16 = heap->heapptr_null16;
45344#else
45345 duk_hstring **lst;
45346#endif
45347
45348 DUK_ASSERT(heap != NULL);
45349
45350 for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
45351 e = heap->strtable + i;
45352
45353 if (e->listlen == 0) {
45354#if defined(DUK_USE_HEAPPTR16)
45355 DUK_DD(DUK_DDPRINT("[%03d] -> plain %d", (int) i, (int) (e->u.str16 != null16 ? 1 : 0)));
45356#else
45357 DUK_DD(DUK_DDPRINT("[%03d] -> plain %d", (int) i, (int) (e->u.str ? 1 : 0)));
45358#endif
45359 } else {
45360 used = 0;
45361#if defined(DUK_USE_HEAPPTR16)
45362 lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
45363#else
45364 lst = e->u.strlist;
45365#endif
45366 DUK_ASSERT(lst != NULL);
45367 for (j = 0, n = e->listlen; j < n; j++) {
45368#if defined(DUK_USE_HEAPPTR16)
45369 if (lst[j] != null16) {
45370#else
45371 if (lst[j] != NULL) {
45372#endif
45373 used++;
45374 }
45375 }
45376 DUK_DD(DUK_DDPRINT("[%03d] -> array %d/%d", (int) i, (int) used, (int) e->listlen));
45377 }
45378 }
45379}
45380#endif /* DUK_USE_DEBUG */
45381
45382#endif /* DUK_USE_STRTAB_CHAIN */
45383
45384/*
45385 * String table algorithm: closed hashing with a probe sequence
45386 *
45387 * This is the default algorithm and works fine for environments with
45388 * minimal memory constraints.
45389 */
45390
45391#if defined(DUK_USE_STRTAB_PROBE)
45392
45393/* Count actually used (non-NULL, non-DELETED) entries. */
45394DUK_LOCAL duk_int_t duk__count_used_probe(duk_heap *heap) {
45395 duk_int_t res = 0;
45396 duk_uint_fast32_t i, n;
45397#if defined(DUK_USE_HEAPPTR16)
45398 duk_uint16_t null16 = heap->heapptr_null16;
45399 duk_uint16_t deleted16 = heap->heapptr_deleted16;
45400#endif
45401
45402 n = (duk_uint_fast32_t) heap->st_size;
45403 for (i = 0; i < n; i++) {
45404#if defined(DUK_USE_HEAPPTR16)
45405 if (heap->strtable16[i] != null16 && heap->strtable16[i] != deleted16) {
45406#else
45407 if (heap->strtable[i] != NULL && heap->strtable[i] != DUK__DELETED_MARKER(heap)) {
45408#endif
45409 res++;
45410 }
45411 }
45412 return res;
45413}
45414
45415#if defined(DUK_USE_HEAPPTR16)
45416DUK_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) {
45417#else
45418DUK_LOCAL void duk__insert_hstring_probe(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, duk_uint32_t *p_used, duk_hstring *h) {
45419#endif
45420 duk_uint32_t i;
45421 duk_uint32_t step;
45422#if defined(DUK_USE_HEAPPTR16)
45423 duk_uint16_t null16 = heap->heapptr_null16;
45424 duk_uint16_t deleted16 = heap->heapptr_deleted16;
45425#endif
45426
45427 DUK_ASSERT(size > 0);
45428
45429 i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(h), size);
45430 step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(h));
45431 for (;;) {
45432#if defined(DUK_USE_HEAPPTR16)
45433 duk_uint16_t e16 = entries16[i];
45434#else
45435 duk_hstring *e = entries[i];
45436#endif
45437
45438#if defined(DUK_USE_HEAPPTR16)
45439 /* XXX: could check for e16 == 0 because NULL is guaranteed to
45440 * encode to zero.
45441 */
45442 if (e16 == null16) {
45443#else
45444 if (e == NULL) {
45445#endif
45446 DUK_DDD(DUK_DDDPRINT("insert hit (null): %ld", (long) i));
45447#if defined(DUK_USE_HEAPPTR16)
45448 entries16[i] = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
45449#else
45450 entries[i] = h;
45451#endif
45452 (*p_used)++;
45453 break;
45454#if defined(DUK_USE_HEAPPTR16)
45455 } else if (e16 == deleted16) {
45456#else
45457 } else if (e == DUK__DELETED_MARKER(heap)) {
45458#endif
45459 /* st_used remains the same, DELETED is counted as used */
45460 DUK_DDD(DUK_DDDPRINT("insert hit (deleted): %ld", (long) i));
45461#if defined(DUK_USE_HEAPPTR16)
45462 entries16[i] = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
45463#else
45464 entries[i] = h;
45465#endif
45466 break;
45467 }
45468 DUK_DDD(DUK_DDDPRINT("insert miss: %ld", (long) i));
45469 i = (i + step) % size;
45470
45471 /* looping should never happen */
45472 DUK_ASSERT(i != DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(h), size));
45473 }
45474}
45475
45476#if defined(DUK_USE_HEAPPTR16)
45477DUK_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) {
45478#else
45479DUK_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) {
45480#endif
45481 duk_uint32_t i;
45482 duk_uint32_t step;
45483
45484 DUK_ASSERT(size > 0);
45485
45486 i = DUK__HASH_INITIAL(strhash, size);
45487 step = DUK__HASH_PROBE_STEP(strhash);
45488 for (;;) {
45489 duk_hstring *e;
45490#if defined(DUK_USE_HEAPPTR16)
45491 e = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, entries16[i]);
45492#else
45493 e = entries[i];
45494#endif
45495
45496 if (!e) {
45497 return NULL;
45498 }
45499 if (e != DUK__DELETED_MARKER(heap) && DUK_HSTRING_GET_BYTELEN(e) == blen) {
11fdf7f2 45500 if (DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(e), (size_t) blen) == 0) {
7c673cae
FG
45501 DUK_DDD(DUK_DDDPRINT("find matching hit: %ld (step %ld, size %ld)",
45502 (long) i, (long) step, (long) size));
45503 return e;
45504 }
45505 }
45506 DUK_DDD(DUK_DDDPRINT("find matching miss: %ld (step %ld, size %ld)",
45507 (long) i, (long) step, (long) size));
45508 i = (i + step) % size;
45509
45510 /* looping should never happen */
45511 DUK_ASSERT(i != DUK__HASH_INITIAL(strhash, size));
45512 }
45513 DUK_UNREACHABLE();
45514}
45515
45516#if defined(DUK_USE_HEAPPTR16)
45517DUK_LOCAL void duk__remove_matching_hstring_probe(duk_heap *heap, duk_uint16_t *entries16, duk_uint32_t size, duk_hstring *h) {
45518#else
45519DUK_LOCAL void duk__remove_matching_hstring_probe(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, duk_hstring *h) {
45520#endif
45521 duk_uint32_t i;
45522 duk_uint32_t step;
45523 duk_uint32_t hash;
45524#if defined(DUK_USE_HEAPPTR16)
45525 duk_uint16_t null16 = heap->heapptr_null16;
45526 duk_uint16_t h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
45527#endif
45528
45529 DUK_ASSERT(size > 0);
45530
45531 hash = DUK_HSTRING_GET_HASH(h);
45532 i = DUK__HASH_INITIAL(hash, size);
45533 step = DUK__HASH_PROBE_STEP(hash);
45534 for (;;) {
45535#if defined(DUK_USE_HEAPPTR16)
45536 duk_uint16_t e16 = entries16[i];
45537#else
45538 duk_hstring *e = entries[i];
45539#endif
45540
45541#if defined(DUK_USE_HEAPPTR16)
45542 if (e16 == null16) {
45543#else
45544 if (!e) {
45545#endif
45546 DUK_UNREACHABLE();
45547 break;
45548 }
45549#if defined(DUK_USE_HEAPPTR16)
45550 if (e16 == h16) {
45551#else
45552 if (e == h) {
45553#endif
45554 /* st_used remains the same, DELETED is counted as used */
45555 DUK_DDD(DUK_DDDPRINT("free matching hit: %ld", (long) i));
45556#if defined(DUK_USE_HEAPPTR16)
45557 entries16[i] = heap->heapptr_deleted16;
45558#else
45559 entries[i] = DUK__DELETED_MARKER(heap);
45560#endif
45561 break;
45562 }
45563
45564 DUK_DDD(DUK_DDDPRINT("free matching miss: %ld", (long) i));
45565 i = (i + step) % size;
45566
45567 /* looping should never happen */
45568 DUK_ASSERT(i != DUK__HASH_INITIAL(hash, size));
45569 }
45570}
45571
45572DUK_LOCAL duk_bool_t duk__resize_strtab_raw_probe(duk_heap *heap, duk_uint32_t new_size) {
11fdf7f2 45573#if defined(DUK_USE_DEBUG)
7c673cae
FG
45574 duk_uint32_t old_used = heap->st_used;
45575#endif
45576 duk_uint32_t old_size = heap->st_size;
45577#if defined(DUK_USE_HEAPPTR16)
45578 duk_uint16_t *old_entries = heap->strtable16;
45579 duk_uint16_t *new_entries = NULL;
45580#else
45581 duk_hstring **old_entries = heap->strtable;
45582 duk_hstring **new_entries = NULL;
45583#endif
45584 duk_uint32_t new_used = 0;
45585 duk_uint32_t i;
45586
11fdf7f2 45587#if defined(DUK_USE_DEBUG)
7c673cae
FG
45588 DUK_UNREF(old_used); /* unused with some debug level combinations */
45589#endif
45590
45591#ifdef DUK_USE_DDDPRINT
45592 DUK_DDD(DUK_DDDPRINT("attempt to resize stringtable: %ld entries, %ld bytes, %ld used, %ld%% load -> %ld entries, %ld bytes, %ld used, %ld%% load",
45593 (long) old_size, (long) (sizeof(duk_hstring *) * old_size), (long) old_used,
45594 (long) (((double) old_used) / ((double) old_size) * 100.0),
45595 (long) new_size, (long) (sizeof(duk_hstring *) * new_size), (long) duk__count_used_probe(heap),
45596 (long) (((double) duk__count_used_probe(heap)) / ((double) new_size) * 100.0)));
45597#endif
45598
45599 DUK_ASSERT(new_size > (duk_uint32_t) duk__count_used_probe(heap)); /* required for rehash to succeed, equality not that useful */
45600 DUK_ASSERT(old_entries);
7c673cae
FG
45601
45602 /*
45603 * The attempt to allocate may cause a GC. Such a GC must not attempt to resize
45604 * the stringtable (though it can be swept); finalizer execution and object
45605 * compaction must also be postponed to avoid the pressure to add strings to the
11fdf7f2 45606 * string table. Call site must prevent these.
7c673cae
FG
45607 */
45608
11fdf7f2
TL
45609#if defined(DUK_USE_MARK_AND_SWEEP)
45610 DUK_ASSERT(heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE);
45611 DUK_ASSERT(heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_FINALIZERS);
45612 DUK_ASSERT(heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_OBJECT_COMPACTION);
7c673cae
FG
45613#endif
45614
45615#if defined(DUK_USE_HEAPPTR16)
45616 new_entries = (duk_uint16_t *) DUK_ALLOC(heap, sizeof(duk_uint16_t) * new_size);
45617#else
45618 new_entries = (duk_hstring **) DUK_ALLOC(heap, sizeof(duk_hstring *) * new_size);
45619#endif
45620
7c673cae
FG
45621 if (!new_entries) {
45622 goto resize_error;
45623 }
45624
11fdf7f2 45625#if defined(DUK_USE_EXPLICIT_NULL_INIT)
7c673cae
FG
45626 for (i = 0; i < new_size; i++) {
45627#if defined(DUK_USE_HEAPPTR16)
45628 new_entries[i] = heap->heapptr_null16;
45629#else
45630 new_entries[i] = NULL;
45631#endif
45632 }
45633#else
45634#if defined(DUK_USE_HEAPPTR16)
45635 /* Relies on NULL encoding to zero. */
45636 DUK_MEMZERO(new_entries, sizeof(duk_uint16_t) * new_size);
45637#else
45638 DUK_MEMZERO(new_entries, sizeof(duk_hstring *) * new_size);
45639#endif
45640#endif
45641
45642 /* Because new_size > duk__count_used_probe(heap), guaranteed to work */
45643 for (i = 0; i < old_size; i++) {
45644 duk_hstring *e;
45645
45646#if defined(DUK_USE_HEAPPTR16)
45647 e = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, old_entries[i]);
45648#else
45649 e = old_entries[i];
45650#endif
45651 if (e == NULL || e == DUK__DELETED_MARKER(heap)) {
45652 continue;
45653 }
45654 /* checking for DUK__DELETED_MARKER is not necessary here, but helper does it now */
45655 duk__insert_hstring_probe(heap, new_entries, new_size, &new_used, e);
45656 }
45657
45658#ifdef DUK_USE_DDPRINT
45659 DUK_DD(DUK_DDPRINT("resized stringtable: %ld entries, %ld bytes, %ld used, %ld%% load -> %ld entries, %ld bytes, %ld used, %ld%% load",
45660 (long) old_size, (long) (sizeof(duk_hstring *) * old_size), (long) old_used,
45661 (long) (((double) old_used) / ((double) old_size) * 100.0),
45662 (long) new_size, (long) (sizeof(duk_hstring *) * new_size), (long) new_used,
45663 (long) (((double) new_used) / ((double) new_size) * 100.0)));
45664#endif
45665
45666#if defined(DUK_USE_HEAPPTR16)
45667 DUK_FREE(heap, heap->strtable16);
45668 heap->strtable16 = new_entries;
45669#else
45670 DUK_FREE(heap, heap->strtable);
45671 heap->strtable = new_entries;
45672#endif
45673 heap->st_size = new_size;
45674 heap->st_used = new_used; /* may be less, since DELETED entries are NULLed by rehash */
45675
45676 return 0; /* OK */
45677
45678 resize_error:
45679 DUK_FREE(heap, new_entries);
45680 return 1; /* FAIL */
45681}
45682
45683DUK_LOCAL duk_bool_t duk__resize_strtab_probe(duk_heap *heap) {
45684 duk_uint32_t new_size;
45685 duk_bool_t ret;
45686
45687 new_size = (duk_uint32_t) duk__count_used_probe(heap);
45688 if (new_size >= 0x80000000UL) {
45689 new_size = DUK_STRTAB_HIGHEST_32BIT_PRIME;
45690 } else {
45691 new_size = duk_util_get_hash_prime(DUK_STRTAB_GROW_ST_SIZE(new_size));
45692 new_size = duk_util_get_hash_prime(new_size);
45693 }
45694 DUK_ASSERT(new_size > 0);
45695
45696 /* rehash even if old and new sizes are the same to get rid of
45697 * DELETED entries.
45698 */
45699
45700 ret = duk__resize_strtab_raw_probe(heap, new_size);
45701
45702 return ret;
45703}
45704
45705DUK_LOCAL duk_bool_t duk__recheck_strtab_size_probe(duk_heap *heap, duk_uint32_t new_used) {
45706 duk_uint32_t new_free;
45707 duk_uint32_t tmp1;
45708 duk_uint32_t tmp2;
45709
45710 DUK_ASSERT(new_used <= heap->st_size); /* grow by at most one */
45711 new_free = heap->st_size - new_used; /* unsigned intentionally */
45712
45713 /* new_free / size <= 1 / DIV <=> new_free <= size / DIV */
45714 /* new_used / size <= 1 / DIV <=> new_used <= size / DIV */
45715
45716 tmp1 = heap->st_size / DUK_STRTAB_MIN_FREE_DIVISOR;
45717 tmp2 = heap->st_size / DUK_STRTAB_MIN_USED_DIVISOR;
45718
45719 if (new_free <= tmp1 || new_used <= tmp2) {
45720 /* load factor too low or high, count actually used entries and resize */
45721 return duk__resize_strtab_probe(heap);
45722 } else {
45723 return 0; /* OK */
45724 }
45725}
45726
45727#if defined(DUK_USE_DEBUG)
45728DUK_INTERNAL void duk_heap_dump_strtab(duk_heap *heap) {
45729 duk_uint32_t i;
45730 duk_hstring *h;
45731
45732 DUK_ASSERT(heap != NULL);
45733#if defined(DUK_USE_HEAPPTR16)
45734 DUK_ASSERT(heap->strtable16 != NULL);
45735#else
45736 DUK_ASSERT(heap->strtable != NULL);
45737#endif
45738 DUK_UNREF(h);
45739
45740 for (i = 0; i < heap->st_size; i++) {
45741#if defined(DUK_USE_HEAPPTR16)
45742 h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->strtable16[i]);
45743#else
45744 h = heap->strtable[i];
45745#endif
45746
45747 DUK_DD(DUK_DDPRINT("[%03d] -> %p", (int) i, (void *) h));
45748 }
45749}
45750#endif /* DUK_USE_DEBUG */
45751
45752#endif /* DUK_USE_STRTAB_PROBE */
45753
45754/*
45755 * Raw intern and lookup
45756 */
45757
45758DUK_LOCAL duk_hstring *duk__do_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) {
45759 duk_hstring *res;
45760 const duk_uint8_t *extdata;
11fdf7f2
TL
45761#if defined(DUK_USE_MARK_AND_SWEEP)
45762 duk_small_uint_t prev_mark_and_sweep_base_flags;
45763#endif
45764
45765 /* Prevent any side effects on the string table and the caller provided
45766 * str/blen arguments while interning is in progress. For example, if
45767 * the caller provided str/blen from a dynamic buffer, a finalizer might
45768 * resize that dynamic buffer, invalidating the call arguments.
45769 */
45770#if defined(DUK_USE_MARK_AND_SWEEP)
45771 DUK_ASSERT((heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE) == 0);
45772 prev_mark_and_sweep_base_flags = heap->mark_and_sweep_base_flags;
45773 DUK__PREVENT_MS_SIDE_EFFECTS(heap);
45774#endif
7c673cae
FG
45775
45776#if defined(DUK_USE_STRTAB_PROBE)
45777 if (duk__recheck_strtab_size_probe(heap, heap->st_used + 1)) {
11fdf7f2 45778 goto failed;
7c673cae
FG
45779 }
45780#endif
45781
45782 /* For manual testing only. */
45783#if 0
45784 {
45785 duk_size_t i;
45786 DUK_PRINTF("INTERN: \"");
45787 for (i = 0; i < blen; i++) {
45788 duk_uint8_t x = str[i];
45789 if (x >= 0x20 && x <= 0x7e && x != '"' && x != '\\') {
45790 DUK_PRINTF("%c", (int) x); /* char: use int cast */
45791 } else {
45792 DUK_PRINTF("\\x%02lx", (long) x);
45793 }
45794 }
45795 DUK_PRINTF("\"\n");
45796 }
45797#endif
45798
45799#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK)
11fdf7f2 45800 extdata = (const duk_uint8_t *) DUK_USE_EXTSTR_INTERN_CHECK(heap->heap_udata, (void *) DUK_LOSE_CONST(str), (duk_size_t) blen);
7c673cae
FG
45801#else
45802 extdata = (const duk_uint8_t *) NULL;
45803#endif
45804 res = duk__alloc_init_hstring(heap, str, blen, strhash, extdata);
45805 if (!res) {
11fdf7f2 45806 goto failed;
7c673cae
FG
45807 }
45808
45809#if defined(DUK_USE_STRTAB_CHAIN)
45810 if (duk__insert_hstring_chain(heap, res)) {
45811 /* failed */
45812 DUK_FREE(heap, res);
11fdf7f2 45813 goto failed;
7c673cae
FG
45814 }
45815#elif defined(DUK_USE_STRTAB_PROBE)
45816 /* guaranteed to succeed */
45817 duk__insert_hstring_probe(heap,
45818#if defined(DUK_USE_HEAPPTR16)
45819 heap->strtable16,
45820#else
45821 heap->strtable,
45822#endif
45823 heap->st_size,
45824 &heap->st_used,
45825 res);
45826#else
45827#error internal error, invalid strtab options
45828#endif
45829
45830 /* Note: hstring is in heap but has refcount zero and is not strongly reachable.
45831 * Caller should increase refcount and make the hstring reachable before any
45832 * operations which require allocation (and possible gc).
45833 */
45834
11fdf7f2
TL
45835 done:
45836#if defined(DUK_USE_MARK_AND_SWEEP)
45837 heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
45838#endif
7c673cae 45839 return res;
11fdf7f2
TL
45840
45841 failed:
45842 res = NULL;
45843 goto done;
7c673cae
FG
45844}
45845
45846DUK_LOCAL duk_hstring *duk__do_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t *out_strhash) {
45847 duk_hstring *res;
45848
45849 DUK_ASSERT(out_strhash);
45850
45851 *out_strhash = duk_heap_hashstring(heap, str, (duk_size_t) blen);
45852
11fdf7f2
TL
45853#if defined(DUK_USE_ROM_STRINGS)
45854 {
45855 duk_small_uint_t i;
45856 /* XXX: This is VERY inefficient now, and should be e.g. a
45857 * binary search or perfect hash, to be fixed.
45858 */
45859 for (i = 0; i < (duk_small_uint_t) (sizeof(duk_rom_strings) / sizeof(duk_hstring *)); i++) {
45860 duk_hstring *romstr;
45861 romstr = (duk_hstring *) DUK_LOSE_CONST(duk_rom_strings[i]);
45862 if (blen == DUK_HSTRING_GET_BYTELEN(romstr) &&
45863 DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(romstr), blen) == 0) {
45864 DUK_DD(DUK_DDPRINT("intern check: rom string: %!O, computed hash 0x%08lx, rom hash 0x%08lx",
45865 romstr, (unsigned long) *out_strhash, (unsigned long) DUK_HSTRING_GET_HASH(romstr)));
45866 DUK_ASSERT(*out_strhash == DUK_HSTRING_GET_HASH(romstr));
45867 *out_strhash = DUK_HSTRING_GET_HASH(romstr);
45868 return romstr;
45869 }
45870 }
45871 }
45872#endif /* DUK_USE_ROM_STRINGS */
45873
7c673cae
FG
45874#if defined(DUK_USE_STRTAB_CHAIN)
45875 res = duk__find_matching_string_chain(heap, str, blen, *out_strhash);
45876#elif defined(DUK_USE_STRTAB_PROBE)
45877 res = duk__find_matching_string_probe(heap,
45878#if defined(DUK_USE_HEAPPTR16)
45879 heap->strtable16,
45880#else
45881 heap->strtable,
45882#endif
45883 heap->st_size,
45884 str,
45885 blen,
45886 *out_strhash);
45887#else
45888#error internal error, invalid strtab options
45889#endif
45890
45891 return res;
45892}
45893
45894/*
45895 * Exposed calls
45896 */
45897
45898#if 0 /*unused*/
45899DUK_INTERNAL duk_hstring *duk_heap_string_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen) {
45900 duk_uint32_t strhash; /* dummy */
45901 return duk__do_lookup(heap, str, blen, &strhash);
45902}
45903#endif
45904
45905DUK_INTERNAL duk_hstring *duk_heap_string_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen) {
45906 duk_hstring *res;
45907 duk_uint32_t strhash;
45908
45909 /* caller is responsible for ensuring this */
45910 DUK_ASSERT(blen <= DUK_HSTRING_MAX_BYTELEN);
45911
45912 res = duk__do_lookup(heap, str, blen, &strhash);
45913 if (res) {
45914 return res;
45915 }
45916
45917 res = duk__do_intern(heap, str, blen, strhash);
45918 return res; /* may be NULL */
45919}
45920
45921DUK_INTERNAL duk_hstring *duk_heap_string_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen) {
45922 duk_hstring *res = duk_heap_string_intern(thr->heap, str, blen);
45923 if (!res) {
11fdf7f2 45924 DUK_ERROR_ALLOC_DEFMSG(thr);
7c673cae
FG
45925 }
45926 return res;
45927}
45928
45929#if 0 /*unused*/
45930DUK_INTERNAL duk_hstring *duk_heap_string_lookup_u32(duk_heap *heap, duk_uint32_t val) {
45931 char buf[DUK_STRTAB_U32_MAX_STRLEN+1];
45932 DUK_SNPRINTF(buf, sizeof(buf), "%lu", (unsigned long) val);
45933 buf[sizeof(buf) - 1] = (char) 0;
45934 DUK_ASSERT(DUK_STRLEN(buf) <= DUK_UINT32_MAX); /* formatted result limited */
45935 return duk_heap_string_lookup(heap, (const duk_uint8_t *) buf, (duk_uint32_t) DUK_STRLEN(buf));
45936}
45937#endif
45938
45939DUK_INTERNAL duk_hstring *duk_heap_string_intern_u32(duk_heap *heap, duk_uint32_t val) {
45940 char buf[DUK_STRTAB_U32_MAX_STRLEN+1];
45941 DUK_SNPRINTF(buf, sizeof(buf), "%lu", (unsigned long) val);
45942 buf[sizeof(buf) - 1] = (char) 0;
45943 DUK_ASSERT(DUK_STRLEN(buf) <= DUK_UINT32_MAX); /* formatted result limited */
45944 return duk_heap_string_intern(heap, (const duk_uint8_t *) buf, (duk_uint32_t) DUK_STRLEN(buf));
45945}
45946
45947DUK_INTERNAL duk_hstring *duk_heap_string_intern_u32_checked(duk_hthread *thr, duk_uint32_t val) {
45948 duk_hstring *res = duk_heap_string_intern_u32(thr->heap, val);
45949 if (!res) {
11fdf7f2 45950 DUK_ERROR_ALLOC_DEFMSG(thr);
7c673cae
FG
45951 }
45952 return res;
45953}
45954
45955/* find and remove string from stringtable; caller must free the string itself */
11fdf7f2 45956#if defined(DUK_USE_REFERENCE_COUNTING)
7c673cae
FG
45957DUK_INTERNAL void duk_heap_string_remove(duk_heap *heap, duk_hstring *h) {
45958 DUK_DDD(DUK_DDDPRINT("remove string from stringtable: %!O", (duk_heaphdr *) h));
45959
45960#if defined(DUK_USE_STRTAB_CHAIN)
45961 duk__remove_matching_hstring_chain(heap, h);
45962#elif defined(DUK_USE_STRTAB_PROBE)
45963 duk__remove_matching_hstring_probe(heap,
45964#if defined(DUK_USE_HEAPPTR16)
45965 heap->strtable16,
45966#else
45967 heap->strtable,
45968#endif
45969 heap->st_size,
45970 h);
45971#else
45972#error internal error, invalid strtab options
45973#endif
45974}
11fdf7f2 45975#endif
7c673cae
FG
45976
45977#if defined(DUK_USE_MARK_AND_SWEEP) && defined(DUK_USE_MS_STRINGTABLE_RESIZE)
45978DUK_INTERNAL void duk_heap_force_strtab_resize(duk_heap *heap) {
11fdf7f2 45979 duk_small_uint_t prev_mark_and_sweep_base_flags;
7c673cae
FG
45980 /* Force a resize so that DELETED entries are eliminated.
45981 * Another option would be duk__recheck_strtab_size_probe();
45982 * but since that happens on every intern anyway, this whole
45983 * check can now be disabled.
45984 */
11fdf7f2
TL
45985
45986 DUK_ASSERT((heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE) == 0);
45987 prev_mark_and_sweep_base_flags = heap->mark_and_sweep_base_flags;
45988 DUK__PREVENT_MS_SIDE_EFFECTS(heap);
45989
7c673cae
FG
45990#if defined(DUK_USE_STRTAB_CHAIN)
45991 DUK_UNREF(heap);
45992#elif defined(DUK_USE_STRTAB_PROBE)
11fdf7f2 45993 (void) duk__resize_strtab_probe(heap);
7c673cae 45994#endif
11fdf7f2
TL
45995
45996 heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
7c673cae
FG
45997}
45998#endif
45999
46000#if defined(DUK_USE_STRTAB_CHAIN)
46001DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap) {
46002 /* Free strings in the stringtable and any allocations needed
46003 * by the stringtable itself.
46004 */
46005 duk_uint_fast32_t i, j;
46006 duk_strtab_entry *e;
46007#if defined(DUK_USE_HEAPPTR16)
46008 duk_uint16_t *lst;
46009 duk_uint16_t null16 = heap->heapptr_null16;
46010#else
46011 duk_hstring **lst;
46012#endif
46013 duk_hstring *h;
46014
46015 for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
46016 e = heap->strtable + i;
46017 if (e->listlen > 0) {
46018#if defined(DUK_USE_HEAPPTR16)
46019 lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
46020#else
46021 lst = e->u.strlist;
46022#endif
46023 DUK_ASSERT(lst != NULL);
46024
46025 for (j = 0; j < e->listlen; j++) {
46026#if defined(DUK_USE_HEAPPTR16)
46027 h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[j]);
46028 lst[j] = null16;
46029#else
46030 h = lst[j];
46031 lst[j] = NULL;
46032#endif
46033 /* strings may have inner refs (extdata) in some cases */
46034 if (h != NULL) {
46035 duk_free_hstring_inner(heap, h);
46036 DUK_FREE(heap, h);
46037 }
46038 }
46039#if defined(DUK_USE_HEAPPTR16)
46040 e->u.strlist16 = null16;
46041#else
46042 e->u.strlist = NULL;
46043#endif
46044 DUK_FREE(heap, lst);
46045 } else {
46046#if defined(DUK_USE_HEAPPTR16)
46047 h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16);
46048 e->u.str16 = null16;
46049#else
46050 h = e->u.str;
46051 e->u.str = NULL;
46052#endif
46053 if (h != NULL) {
46054 duk_free_hstring_inner(heap, h);
46055 DUK_FREE(heap, h);
46056 }
46057 }
46058 e->listlen = 0;
46059 }
46060}
46061#endif /* DUK_USE_STRTAB_CHAIN */
46062
46063#if defined(DUK_USE_STRTAB_PROBE)
46064DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap) {
46065 duk_uint_fast32_t i;
46066 duk_hstring *h;
46067
46068#if defined(DUK_USE_HEAPPTR16)
46069 if (heap->strtable16) {
46070#else
46071 if (heap->strtable) {
46072#endif
46073 for (i = 0; i < (duk_uint_fast32_t) heap->st_size; i++) {
46074#if defined(DUK_USE_HEAPPTR16)
46075 h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]);
46076#else
46077 h = heap->strtable[i];
46078#endif
46079 if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) {
46080 continue;
46081 }
46082 DUK_ASSERT(h != NULL);
46083
46084 /* strings may have inner refs (extdata) in some cases */
46085 duk_free_hstring_inner(heap, h);
46086 DUK_FREE(heap, h);
46087#if 0 /* not strictly necessary */
46088 heap->strtable[i] = NULL;
46089#endif
46090 }
46091#if defined(DUK_USE_HEAPPTR16)
46092 DUK_FREE(heap, heap->strtable16);
46093#else
46094 DUK_FREE(heap, heap->strtable);
46095#endif
46096#if 0 /* not strictly necessary */
46097 heap->strtable = NULL;
46098#endif
46099 }
46100}
46101#endif /* DUK_USE_STRTAB_PROBE */
46102
46103/* Undefine local defines */
46104#undef DUK__HASH_INITIAL
46105#undef DUK__HASH_PROBE_STEP
46106#undef DUK__DELETED_MARKER
7c673cae
FG
46107/*
46108 * Hobject allocation.
46109 *
46110 * Provides primitive allocation functions for all object types (plain object,
46111 * compiled function, native function, thread). The object return is not yet
46112 * in "heap allocated" list and has a refcount of zero, so caller must careful.
46113 */
46114
46115/* include removed: duk_internal.h */
46116
46117DUK_LOCAL void duk__init_object_parts(duk_heap *heap, duk_hobject *obj, duk_uint_t hobject_flags) {
46118#ifdef DUK_USE_EXPLICIT_NULL_INIT
46119 DUK_HOBJECT_SET_PROPS(heap, obj, NULL);
46120#endif
46121
46122 /* XXX: macro? sets both heaphdr and object flags */
46123 obj->hdr.h_flags = hobject_flags;
46124 DUK_HEAPHDR_SET_TYPE(&obj->hdr, DUK_HTYPE_OBJECT); /* also goes into flags */
46125
46126#if defined(DUK_USE_HEAPPTR16)
46127 /* Zero encoded pointer is required to match NULL */
46128 DUK_HEAPHDR_SET_NEXT(heap, &obj->hdr, NULL);
46129#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
46130 DUK_HEAPHDR_SET_PREV(heap, &obj->hdr, NULL);
46131#endif
46132#endif
11fdf7f2
TL
46133 DUK_ASSERT_HEAPHDR_LINKS(heap, &obj->hdr);
46134 DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &obj->hdr);
7c673cae
FG
46135
46136 /*
46137 * obj->props is intentionally left as NULL, and duk_hobject_props.c must deal
46138 * with this properly. This is intentional: empty objects consume a minimum
46139 * amount of memory. Further, an initial allocation might fail and cause
46140 * 'obj' to "leak" (require a mark-and-sweep) since it is not reachable yet.
46141 */
46142}
46143
46144/*
46145 * Allocate an duk_hobject.
46146 *
46147 * The allocated object has no allocation for properties; the caller may
46148 * want to force a resize if a desired size is known.
46149 *
46150 * The allocated object has zero reference count and is not reachable.
46151 * The caller MUST make the object reachable and increase its reference
46152 * count before invoking any operation that might require memory allocation.
46153 */
46154
46155DUK_INTERNAL duk_hobject *duk_hobject_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
46156 duk_hobject *res;
46157
46158 DUK_ASSERT(heap != NULL);
46159
46160 /* different memory layout, alloc size, and init */
46161 DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_COMPILEDFUNCTION) == 0);
46162 DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_NATIVEFUNCTION) == 0);
46163 DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_THREAD) == 0);
46164
46165 res = (duk_hobject *) DUK_ALLOC(heap, sizeof(duk_hobject));
46166 if (!res) {
46167 return NULL;
46168 }
46169 DUK_MEMZERO(res, sizeof(duk_hobject));
46170
46171 duk__init_object_parts(heap, res, hobject_flags);
46172
46173 return res;
46174}
46175
46176DUK_INTERNAL duk_hcompiledfunction *duk_hcompiledfunction_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
46177 duk_hcompiledfunction *res;
46178
46179 res = (duk_hcompiledfunction *) DUK_ALLOC(heap, sizeof(duk_hcompiledfunction));
46180 if (!res) {
46181 return NULL;
46182 }
46183 DUK_MEMZERO(res, sizeof(duk_hcompiledfunction));
46184
46185 duk__init_object_parts(heap, &res->obj, hobject_flags);
46186
46187#ifdef DUK_USE_EXPLICIT_NULL_INIT
46188#ifdef DUK_USE_HEAPPTR16
46189 /* NULL pointer is required to encode to zero, so memset is enough. */
46190#else
46191 res->data = NULL;
46192 res->funcs = NULL;
46193 res->bytecode = NULL;
46194#endif
46195#endif
46196
46197 return res;
46198}
46199
46200DUK_INTERNAL duk_hnativefunction *duk_hnativefunction_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
46201 duk_hnativefunction *res;
46202
46203 res = (duk_hnativefunction *) DUK_ALLOC(heap, sizeof(duk_hnativefunction));
46204 if (!res) {
46205 return NULL;
46206 }
46207 DUK_MEMZERO(res, sizeof(duk_hnativefunction));
46208
46209 duk__init_object_parts(heap, &res->obj, hobject_flags);
46210
46211#ifdef DUK_USE_EXPLICIT_NULL_INIT
46212 res->func = NULL;
46213#endif
46214
46215 return res;
46216}
46217
46218DUK_INTERNAL duk_hbufferobject *duk_hbufferobject_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
46219 duk_hbufferobject *res;
46220
46221 res = (duk_hbufferobject *) DUK_ALLOC(heap, sizeof(duk_hbufferobject));
46222 if (!res) {
46223 return NULL;
46224 }
46225 DUK_MEMZERO(res, sizeof(duk_hbufferobject));
46226
46227 duk__init_object_parts(heap, &res->obj, hobject_flags);
46228
46229#ifdef DUK_USE_EXPLICIT_NULL_INIT
46230 res->buf = NULL;
46231#endif
46232
46233 DUK_ASSERT_HBUFFEROBJECT_VALID(res);
46234 return res;
46235}
46236
46237/*
46238 * Allocate a new thread.
46239 *
46240 * Leaves the built-ins array uninitialized. The caller must either
46241 * initialize a new global context or share existing built-ins from
46242 * another thread.
46243 */
46244
46245DUK_INTERNAL duk_hthread *duk_hthread_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
46246 duk_hthread *res;
46247
46248 res = (duk_hthread *) DUK_ALLOC(heap, sizeof(duk_hthread));
46249 if (!res) {
46250 return NULL;
46251 }
46252 DUK_MEMZERO(res, sizeof(duk_hthread));
46253
46254 duk__init_object_parts(heap, &res->obj, hobject_flags);
46255
46256#ifdef DUK_USE_EXPLICIT_NULL_INIT
46257 res->ptr_curr_pc = NULL;
46258 res->heap = NULL;
46259 res->valstack = NULL;
46260 res->valstack_end = NULL;
46261 res->valstack_bottom = NULL;
46262 res->valstack_top = NULL;
46263 res->callstack = NULL;
46264 res->catchstack = NULL;
46265 res->resumer = NULL;
46266 res->compile_ctx = NULL,
46267#ifdef DUK_USE_HEAPPTR16
46268 res->strs16 = NULL;
46269#else
46270 res->strs = NULL;
46271#endif
46272 {
46273 int i;
46274 for (i = 0; i < DUK_NUM_BUILTINS; i++) {
46275 res->builtins[i] = NULL;
46276 }
46277 }
46278#endif
46279 /* when nothing is running, API calls are in non-strict mode */
46280 DUK_ASSERT(res->strict == 0);
46281
46282 res->heap = heap;
46283 res->valstack_max = DUK_VALSTACK_DEFAULT_MAX;
46284 res->callstack_max = DUK_CALLSTACK_DEFAULT_MAX;
46285 res->catchstack_max = DUK_CATCHSTACK_DEFAULT_MAX;
46286
46287 return res;
46288}
46289
46290#if 0 /* unused now */
46291DUK_INTERNAL duk_hobject *duk_hobject_alloc_checked(duk_hthread *thr, duk_uint_t hobject_flags) {
46292 duk_hobject *res = duk_hobject_alloc(thr->heap, hobject_flags);
46293 if (!res) {
11fdf7f2 46294 DUK_ERROR_ALLOC_DEFMSG(thr);
7c673cae
FG
46295 }
46296 return res;
46297}
46298#endif
7c673cae
FG
46299/*
46300 * Hobject enumeration support.
46301 *
46302 * Creates an internal enumeration state object to be used e.g. with for-in
46303 * enumeration. The state object contains a snapshot of target object keys
46304 * and internal control state for enumeration. Enumerator flags allow caller
46305 * to e.g. request internal/non-enumerable properties, and to enumerate only
46306 * "own" properties.
46307 *
46308 * Also creates the result value for e.g. Object.keys() based on the same
46309 * internal structure.
46310 *
46311 * This snapshot-based enumeration approach is used to simplify enumeration:
46312 * non-snapshot-based approaches are difficult to reconcile with mutating
46313 * the enumeration target, running multiple long-lived enumerators at the
46314 * same time, garbage collection details, etc. The downside is that the
46315 * enumerator object is memory inefficient especially for iterating arrays.
46316 */
46317
46318/* include removed: duk_internal.h */
46319
46320/* XXX: identify enumeration target with an object index (not top of stack) */
46321
46322/* must match exactly the number of internal properties inserted to enumerator */
46323#define DUK__ENUM_START_INDEX 2
46324
46325DUK_LOCAL const duk_uint16_t duk__bufferobject_virtual_props[] = {
46326 DUK_STRIDX_LENGTH,
46327 DUK_STRIDX_BYTE_LENGTH,
46328 DUK_STRIDX_BYTE_OFFSET,
46329 DUK_STRIDX_BYTES_PER_ELEMENT
46330};
46331
46332/*
46333 * Helper to sort array index keys. The keys are in the enumeration object
46334 * entry part, starting from DUK__ENUM_START_INDEX, and the entry part is dense.
46335 *
46336 * We use insertion sort because it is simple (leading to compact code,)
46337 * works nicely in-place, and minimizes operations if data is already sorted
46338 * or nearly sorted (which is a very common case here). It also minimizes
46339 * the use of element comparisons in general. This is nice because element
46340 * comparisons here involve re-parsing the string keys into numbers each
46341 * time, which is naturally very expensive.
46342 *
46343 * Note that the entry part values are all "true", e.g.
46344 *
46345 * "1" -> true, "3" -> true, "2" -> true
46346 *
46347 * so it suffices to only work in the key part without exchanging any keys,
46348 * simplifying the sort.
46349 *
46350 * http://en.wikipedia.org/wiki/Insertion_sort
46351 *
46352 * (Compiles to about 160 bytes now as a stand-alone function.)
46353 */
46354
46355DUK_LOCAL void duk__sort_array_indices(duk_hthread *thr, duk_hobject *h_obj) {
46356 duk_hstring **keys;
46357 duk_hstring **p_curr, **p_insert, **p_end;
46358 duk_hstring *h_curr;
46359 duk_uarridx_t val_highest, val_curr, val_insert;
46360
46361 DUK_ASSERT(h_obj != NULL);
46362 DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(h_obj) >= 2); /* control props */
46363 DUK_UNREF(thr);
46364
46365 if (DUK_HOBJECT_GET_ENEXT(h_obj) <= 1 + DUK__ENUM_START_INDEX) {
46366 return;
46367 }
46368
46369 keys = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, h_obj);
46370 p_end = keys + DUK_HOBJECT_GET_ENEXT(h_obj);
46371 keys += DUK__ENUM_START_INDEX;
46372
46373 DUK_DDD(DUK_DDDPRINT("keys=%p, p_end=%p (after skipping enum props)",
46374 (void *) keys, (void *) p_end));
46375
46376#ifdef DUK_USE_DDDPRINT
46377 {
46378 duk_uint_fast32_t i;
46379 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h_obj); i++) {
46380 DUK_DDD(DUK_DDDPRINT("initial: %ld %p -> %!O",
46381 (long) i,
46382 (void *) DUK_HOBJECT_E_GET_KEY_PTR(thr->heap, h_obj, i),
46383 (duk_heaphdr *) DUK_HOBJECT_E_GET_KEY(thr->heap, h_obj, i)));
46384 }
46385 }
46386#endif
46387
46388 val_highest = DUK_HSTRING_GET_ARRIDX_SLOW(keys[0]);
46389 for (p_curr = keys + 1; p_curr < p_end; p_curr++) {
46390 DUK_ASSERT(*p_curr != NULL);
46391 val_curr = DUK_HSTRING_GET_ARRIDX_SLOW(*p_curr);
46392
46393 if (val_curr >= val_highest) {
46394 DUK_DDD(DUK_DDDPRINT("p_curr=%p, p_end=%p, val_highest=%ld, val_curr=%ld -> "
46395 "already in correct order, next",
46396 (void *) p_curr, (void *) p_end, (long) val_highest, (long) val_curr));
46397 val_highest = val_curr;
46398 continue;
46399 }
46400
46401 DUK_DDD(DUK_DDDPRINT("p_curr=%p, p_end=%p, val_highest=%ld, val_curr=%ld -> "
46402 "needs to be inserted",
46403 (void *) p_curr, (void *) p_end, (long) val_highest, (long) val_curr));
46404
46405 /* Needs to be inserted; scan backwards, since we optimize
46406 * for the case where elements are nearly in order.
46407 */
46408
46409 p_insert = p_curr - 1;
46410 for (;;) {
46411 val_insert = DUK_HSTRING_GET_ARRIDX_SLOW(*p_insert);
46412 if (val_insert < val_curr) {
46413 DUK_DDD(DUK_DDDPRINT("p_insert=%p, val_insert=%ld, val_curr=%ld -> insert after this",
46414 (void *) p_insert, (long) val_insert, (long) val_curr));
46415 p_insert++;
46416 break;
46417 }
46418 if (p_insert == keys) {
46419 DUK_DDD(DUK_DDDPRINT("p_insert=%p -> out of keys, insert to beginning", (void *) p_insert));
46420 break;
46421 }
46422 DUK_DDD(DUK_DDDPRINT("p_insert=%p, val_insert=%ld, val_curr=%ld -> search backwards",
46423 (void *) p_insert, (long) val_insert, (long) val_curr));
46424 p_insert--;
46425 }
46426
46427 DUK_DDD(DUK_DDDPRINT("final p_insert=%p", (void *) p_insert));
46428
46429 /* .-- p_insert .-- p_curr
46430 * v v
46431 * | ... | insert | ... | curr
46432 */
46433
46434 h_curr = *p_curr;
46435 DUK_DDD(DUK_DDDPRINT("memmove: dest=%p, src=%p, size=%ld, h_curr=%p",
46436 (void *) (p_insert + 1), (void *) p_insert,
46437 (long) (p_curr - p_insert), (void *) h_curr));
46438
46439 DUK_MEMMOVE((void *) (p_insert + 1),
11fdf7f2 46440 (const void *) p_insert,
7c673cae
FG
46441 (size_t) ((p_curr - p_insert) * sizeof(duk_hstring *)));
46442 *p_insert = h_curr;
46443 /* keep val_highest */
46444 }
46445
46446#ifdef DUK_USE_DDDPRINT
46447 {
46448 duk_uint_fast32_t i;
46449 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h_obj); i++) {
46450 DUK_DDD(DUK_DDDPRINT("final: %ld %p -> %!O",
46451 (long) i,
46452 (void *) DUK_HOBJECT_E_GET_KEY_PTR(thr->heap, h_obj, i),
46453 (duk_heaphdr *) DUK_HOBJECT_E_GET_KEY(thr->heap, h_obj, i)));
46454 }
46455 }
46456#endif
46457}
46458
46459/*
46460 * Create an internal enumerator object E, which has its keys ordered
46461 * to match desired enumeration ordering. Also initialize internal control
46462 * properties for enumeration.
46463 *
46464 * Note: if an array was used to hold enumeration keys instead, an array
46465 * scan would be needed to eliminate duplicates found in the prototype chain.
46466 */
46467
46468DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint_t enum_flags) {
46469 duk_hthread *thr = (duk_hthread *) ctx;
46470 duk_hobject *enum_target;
46471 duk_hobject *curr;
46472 duk_hobject *res;
46473#if defined(DUK_USE_ES6_PROXY)
46474 duk_hobject *h_proxy_target;
46475 duk_hobject *h_proxy_handler;
46476 duk_hobject *h_trap_result;
46477#endif
46478 duk_uint_fast32_t i, len; /* used for array, stack, and entry indices */
46479
46480 DUK_ASSERT(ctx != NULL);
46481
46482 DUK_DDD(DUK_DDDPRINT("create enumerator, stack top: %ld", (long) duk_get_top(ctx)));
46483
46484 enum_target = duk_require_hobject(ctx, -1);
46485 DUK_ASSERT(enum_target != NULL);
46486
46487 duk_push_object_internal(ctx);
46488 res = duk_require_hobject(ctx, -1);
46489
46490 DUK_DDD(DUK_DDDPRINT("created internal object"));
46491
46492 /* [enum_target res] */
46493
46494 /* Target must be stored so that we can recheck whether or not
46495 * keys still exist when we enumerate. This is not done if the
46496 * enumeration result comes from a proxy trap as there is no
46497 * real object to check against.
46498 */
46499 duk_push_hobject(ctx, enum_target);
46500 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_INT_TARGET);
46501
46502 /* Initialize index so that we skip internal control keys. */
46503 duk_push_int(ctx, DUK__ENUM_START_INDEX);
46504 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_INT_NEXT);
46505
46506 /*
46507 * Proxy object handling
46508 */
46509
46510#if defined(DUK_USE_ES6_PROXY)
46511 if (DUK_LIKELY((enum_flags & DUK_ENUM_NO_PROXY_BEHAVIOR) != 0)) {
46512 goto skip_proxy;
46513 }
46514 if (DUK_LIKELY(!duk_hobject_proxy_check(thr,
46515 enum_target,
46516 &h_proxy_target,
46517 &h_proxy_handler))) {
46518 goto skip_proxy;
46519 }
46520
46521 DUK_DDD(DUK_DDDPRINT("proxy enumeration"));
46522 duk_push_hobject(ctx, h_proxy_handler);
46523 if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_ENUMERATE)) {
46524 /* No need to replace the 'enum_target' value in stack, only the
46525 * enum_target reference. This also ensures that the original
46526 * enum target is reachable, which keeps the proxy and the proxy
46527 * target reachable. We do need to replace the internal _Target.
46528 */
46529 DUK_DDD(DUK_DDDPRINT("no enumerate trap, enumerate proxy target instead"));
46530 DUK_DDD(DUK_DDDPRINT("h_proxy_target=%!O", (duk_heaphdr *) h_proxy_target));
46531 enum_target = h_proxy_target;
46532
46533 duk_push_hobject(ctx, enum_target); /* -> [ ... enum_target res handler undefined target ] */
46534 duk_put_prop_stridx(ctx, -4, DUK_STRIDX_INT_TARGET);
46535
46536 duk_pop_2(ctx); /* -> [ ... enum_target res ] */
46537 goto skip_proxy;
46538 }
46539
46540 /* [ ... enum_target res handler trap ] */
46541 duk_insert(ctx, -2);
46542 duk_push_hobject(ctx, h_proxy_target); /* -> [ ... enum_target res trap handler target ] */
46543 duk_call_method(ctx, 1 /*nargs*/); /* -> [ ... enum_target res trap_result ] */
46544 h_trap_result = duk_require_hobject(ctx, -1);
46545 DUK_UNREF(h_trap_result);
46546
46547 /* Copy trap result keys into the enumerator object. */
46548 len = (duk_uint_fast32_t) duk_get_length(ctx, -1);
46549 for (i = 0; i < len; i++) {
46550 /* XXX: not sure what the correct semantic details are here,
46551 * e.g. handling of missing values (gaps), handling of non-array
46552 * trap results, etc.
46553 *
46554 * For keys, we simply skip non-string keys which seems to be
46555 * consistent with how e.g. Object.keys() will process proxy trap
46556 * results (ES6, Section 19.1.2.14).
46557 */
46558 if (duk_get_prop_index(ctx, -1, i) && duk_is_string(ctx, -1)) {
46559 /* [ ... enum_target res trap_result val ] */
46560 duk_push_true(ctx);
46561 /* [ ... enum_target res trap_result val true ] */
46562 duk_put_prop(ctx, -4);
46563 } else {
46564 duk_pop(ctx);
46565 }
46566 }
46567 /* [ ... enum_target res trap_result ] */
46568 duk_pop(ctx);
46569 duk_remove(ctx, -2);
46570
46571 /* [ ... res ] */
46572
46573 /* The internal _Target property is kept pointing to the original
46574 * enumeration target (the proxy object), so that the enumerator
46575 * 'next' operation can read property values if so requested. The
46576 * fact that the _Target is a proxy disables key existence check
46577 * during enumeration.
46578 */
46579 DUK_DDD(DUK_DDDPRINT("proxy enumeration, final res: %!O", (duk_heaphdr *) res));
46580 goto compact_and_return;
46581
46582 skip_proxy:
46583#endif /* DUK_USE_ES6_PROXY */
46584
46585 curr = enum_target;
46586 while (curr) {
46587 /*
46588 * Virtual properties.
46589 *
46590 * String and buffer indices are virtual and always enumerable,
46591 * 'length' is virtual and non-enumerable. Array and arguments
46592 * object props have special behavior but are concrete.
46593 */
46594
46595 if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr) ||
46596 DUK_HOBJECT_IS_BUFFEROBJECT(curr)) {
46597 /* String and buffer enumeration behavior is identical now,
46598 * so use shared handler.
46599 */
46600 if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr)) {
46601 duk_hstring *h_val;
46602 h_val = duk_hobject_get_internal_value_string(thr->heap, curr);
46603 DUK_ASSERT(h_val != NULL); /* string objects must not created without internal value */
46604 len = (duk_uint_fast32_t) DUK_HSTRING_GET_CHARLEN(h_val);
46605 } else {
46606 duk_hbufferobject *h_bufobj;
46607 DUK_ASSERT(DUK_HOBJECT_IS_BUFFEROBJECT(curr));
46608 h_bufobj = (duk_hbufferobject *) curr;
46609 if (h_bufobj == NULL) {
46610 /* Neutered buffer, zero length seems
46611 * like good behavior here.
46612 */
46613 len = 0;
46614 } else {
46615 /* There's intentionally no check for
46616 * current underlying buffer length.
46617 */
46618 len = (duk_uint_fast32_t) (h_bufobj->length >> h_bufobj->shift);
46619 }
46620 }
46621
46622 for (i = 0; i < len; i++) {
46623 duk_hstring *k;
46624
46625 k = duk_heap_string_intern_u32_checked(thr, i);
46626 DUK_ASSERT(k);
46627 duk_push_hstring(ctx, k);
46628 duk_push_true(ctx);
46629
46630 /* [enum_target res key true] */
46631 duk_put_prop(ctx, -3);
46632
46633 /* [enum_target res] */
46634 }
46635
46636 /* 'length' and other virtual properties are not
46637 * enumerable, but are included if non-enumerable
46638 * properties are requested.
46639 */
46640
46641 if (enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE) {
46642 duk_uint_fast32_t n;
46643
46644 if (DUK_HOBJECT_IS_BUFFEROBJECT(curr)) {
46645 n = sizeof(duk__bufferobject_virtual_props) / sizeof(duk_uint16_t);
46646 } else {
46647 DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr));
46648 DUK_ASSERT(duk__bufferobject_virtual_props[0] == DUK_STRIDX_LENGTH);
46649 n = 1; /* only 'length' */
46650 }
46651
46652 for (i = 0; i < n; i++) {
46653 duk_push_hstring_stridx(ctx, duk__bufferobject_virtual_props[i]);
46654 duk_push_true(ctx);
46655 duk_put_prop(ctx, -3);
46656 }
46657
46658 }
46659 } else if (DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(curr)) {
46660 if (enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE) {
46661 duk_push_hstring_stridx(ctx, DUK_STRIDX_LENGTH);
46662 duk_push_true(ctx);
46663 duk_put_prop(ctx, -3);
46664 }
46665 }
46666
46667 /*
46668 * Array part
46669 *
46670 * Note: ordering between array and entry part must match 'abandon array'
46671 * behavior in duk_hobject_props.c: key order after an array is abandoned
46672 * must be the same.
46673 */
46674
46675 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(curr); i++) {
46676 duk_hstring *k;
46677 duk_tval *tv;
46678
46679 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, curr, i);
11fdf7f2 46680 if (DUK_TVAL_IS_UNUSED(tv)) {
7c673cae
FG
46681 continue;
46682 }
46683 k = duk_heap_string_intern_u32_checked(thr, i);
46684 DUK_ASSERT(k);
46685
46686 duk_push_hstring(ctx, k);
46687 duk_push_true(ctx);
46688
46689 /* [enum_target res key true] */
46690 duk_put_prop(ctx, -3);
46691
46692 /* [enum_target res] */
46693 }
46694
46695 /*
46696 * Entries part
46697 */
46698
46699 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(curr); i++) {
46700 duk_hstring *k;
46701
46702 k = DUK_HOBJECT_E_GET_KEY(thr->heap, curr, i);
46703 if (!k) {
46704 continue;
46705 }
46706 if (!DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(thr->heap, curr, i) &&
46707 !(enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE)) {
46708 continue;
46709 }
46710 if (DUK_HSTRING_HAS_INTERNAL(k) &&
46711 !(enum_flags & DUK_ENUM_INCLUDE_INTERNAL)) {
46712 continue;
46713 }
46714 if ((enum_flags & DUK_ENUM_ARRAY_INDICES_ONLY) &&
46715 (DUK_HSTRING_GET_ARRIDX_SLOW(k) == DUK_HSTRING_NO_ARRAY_INDEX)) {
46716 continue;
46717 }
46718
46719 DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, curr, i) ||
11fdf7f2 46720 !DUK_TVAL_IS_UNUSED(&DUK_HOBJECT_E_GET_VALUE_PTR(thr->heap, curr, i)->v));
7c673cae
FG
46721
46722 duk_push_hstring(ctx, k);
46723 duk_push_true(ctx);
46724
46725 /* [enum_target res key true] */
46726 duk_put_prop(ctx, -3);
46727
46728 /* [enum_target res] */
46729 }
46730
46731 if (enum_flags & DUK_ENUM_OWN_PROPERTIES_ONLY) {
46732 break;
46733 }
46734
46735 curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
46736 }
46737
46738 /* [enum_target res] */
46739
46740 duk_remove(ctx, -2);
46741
46742 /* [res] */
46743
46744 if ((enum_flags & (DUK_ENUM_ARRAY_INDICES_ONLY | DUK_ENUM_SORT_ARRAY_INDICES)) ==
46745 (DUK_ENUM_ARRAY_INDICES_ONLY | DUK_ENUM_SORT_ARRAY_INDICES)) {
46746 /*
46747 * Some E5/E5.1 algorithms require that array indices are iterated
46748 * in a strictly ascending order. This is the case for e.g.
46749 * Array.prototype.forEach() and JSON.stringify() PropertyList
46750 * handling.
46751 *
46752 * To ensure this property for arrays with an array part (and
46753 * arbitrary objects too, since e.g. forEach() can be applied
46754 * to an array), the caller can request that we sort the keys
46755 * here.
46756 */
46757
46758 /* XXX: avoid this at least when enum_target is an Array, it has an
46759 * array part, and no ancestor properties were included? Not worth
46760 * it for JSON, but maybe worth it for forEach().
46761 */
46762
46763 /* XXX: may need a 'length' filter for forEach()
46764 */
46765 DUK_DDD(DUK_DDDPRINT("sort array indices by caller request"));
46766 duk__sort_array_indices(thr, res);
46767 }
46768
46769#if defined(DUK_USE_ES6_PROXY)
46770 compact_and_return:
46771#endif
46772 /* compact; no need to seal because object is internal */
46773 duk_hobject_compact_props(thr, res);
46774
46775 DUK_DDD(DUK_DDDPRINT("created enumerator object: %!iT", (duk_tval *) duk_get_tval(ctx, -1)));
46776}
46777
46778/*
46779 * Returns non-zero if a key and/or value was enumerated, and:
46780 *
46781 * [enum] -> [key] (get_value == 0)
46782 * [enum] -> [key value] (get_value == 1)
46783 *
46784 * Returns zero without pushing anything on the stack otherwise.
46785 */
46786DUK_INTERNAL duk_bool_t duk_hobject_enumerator_next(duk_context *ctx, duk_bool_t get_value) {
46787 duk_hthread *thr = (duk_hthread *) ctx;
46788 duk_hobject *e;
46789 duk_hobject *enum_target;
46790 duk_hstring *res = NULL;
46791 duk_uint_fast32_t idx;
46792 duk_bool_t check_existence;
46793
46794 DUK_ASSERT(ctx != NULL);
46795
46796 /* [... enum] */
46797
46798 e = duk_require_hobject(ctx, -1);
46799
46800 /* XXX use get tval ptr, more efficient */
46801 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_NEXT);
46802 idx = (duk_uint_fast32_t) duk_require_uint(ctx, -1);
46803 duk_pop(ctx);
46804 DUK_DDD(DUK_DDDPRINT("enumeration: index is: %ld", (long) idx));
46805
46806 /* Enumeration keys are checked against the enumeration target (to see
46807 * that they still exist). In the proxy enumeration case _Target will
46808 * be the proxy, and checking key existence against the proxy is not
46809 * required (or sensible, as the keys may be fully virtual).
46810 */
46811 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TARGET);
46812 enum_target = duk_require_hobject(ctx, -1);
46813 DUK_ASSERT(enum_target != NULL);
46814#if defined(DUK_USE_ES6_PROXY)
46815 check_existence = (!DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(enum_target));
46816#else
46817 check_existence = 1;
46818#endif
46819 duk_pop(ctx); /* still reachable */
46820
46821 DUK_DDD(DUK_DDDPRINT("getting next enum value, enum_target=%!iO, enumerator=%!iT",
46822 (duk_heaphdr *) enum_target, (duk_tval *) duk_get_tval(ctx, -1)));
46823
46824 /* no array part */
46825 for (;;) {
46826 duk_hstring *k;
46827
46828 if (idx >= DUK_HOBJECT_GET_ENEXT(e)) {
46829 DUK_DDD(DUK_DDDPRINT("enumeration: ran out of elements"));
46830 break;
46831 }
46832
46833 /* we know these because enum objects are internally created */
46834 k = DUK_HOBJECT_E_GET_KEY(thr->heap, e, idx);
46835 DUK_ASSERT(k != NULL);
46836 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, e, idx));
11fdf7f2 46837 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(&DUK_HOBJECT_E_GET_VALUE(thr->heap, e, idx).v));
7c673cae
FG
46838
46839 idx++;
46840
46841 /* recheck that the property still exists */
46842 if (check_existence && !duk_hobject_hasprop_raw(thr, enum_target, k)) {
46843 DUK_DDD(DUK_DDDPRINT("property deleted during enumeration, skip"));
46844 continue;
46845 }
46846
46847 DUK_DDD(DUK_DDDPRINT("enumeration: found element, key: %!O", (duk_heaphdr *) k));
46848 res = k;
46849 break;
46850 }
46851
46852 DUK_DDD(DUK_DDDPRINT("enumeration: updating next index to %ld", (long) idx));
46853
46854 duk_push_u32(ctx, (duk_uint32_t) idx);
46855 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_INT_NEXT);
46856
46857 /* [... enum] */
46858
46859 if (res) {
46860 duk_push_hstring(ctx, res);
46861 if (get_value) {
46862 duk_push_hobject(ctx, enum_target);
46863 duk_dup(ctx, -2); /* -> [... enum key enum_target key] */
46864 duk_get_prop(ctx, -2); /* -> [... enum key enum_target val] */
46865 duk_remove(ctx, -2); /* -> [... enum key val] */
46866 duk_remove(ctx, -3); /* -> [... key val] */
46867 } else {
46868 duk_remove(ctx, -2); /* -> [... key] */
46869 }
46870 return 1;
46871 } else {
46872 duk_pop(ctx); /* -> [...] */
46873 return 0;
46874 }
46875}
46876
46877/*
46878 * Get enumerated keys in an Ecmascript array. Matches Object.keys() behavior
46879 * described in E5 Section 15.2.3.14.
46880 */
46881
46882DUK_INTERNAL duk_ret_t duk_hobject_get_enumerated_keys(duk_context *ctx, duk_small_uint_t enum_flags) {
46883 duk_hthread *thr = (duk_hthread *) ctx;
46884 duk_hobject *e;
46885 duk_uint_fast32_t i;
46886 duk_uint_fast32_t idx;
46887
46888 DUK_ASSERT(ctx != NULL);
46889 DUK_ASSERT(duk_get_hobject(ctx, -1) != NULL);
46890 DUK_UNREF(thr);
46891
46892 /* Create a temporary enumerator to get the (non-duplicated) key list;
46893 * the enumerator state is initialized without being needed, but that
46894 * has little impact.
46895 */
46896
46897 duk_hobject_enumerator_create(ctx, enum_flags);
46898 duk_push_array(ctx);
46899
46900 /* [enum_target enum res] */
46901
46902 e = duk_require_hobject(ctx, -2);
46903 DUK_ASSERT(e != NULL);
46904
46905 idx = 0;
46906 for (i = DUK__ENUM_START_INDEX; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(e); i++) {
46907 duk_hstring *k;
46908
46909 k = DUK_HOBJECT_E_GET_KEY(thr->heap, e, i);
46910 DUK_ASSERT(k); /* enumerator must have no keys deleted */
46911
46912 /* [enum_target enum res] */
46913 duk_push_hstring(ctx, k);
46914 duk_put_prop_index(ctx, -2, idx);
46915 idx++;
46916 }
46917
46918 /* [enum_target enum res] */
46919 duk_remove(ctx, -2);
46920
46921 /* [enum_target res] */
46922
46923 return 1; /* return 1 to allow callers to tail call */
46924}
7c673cae
FG
46925/*
46926 * Run an duk_hobject finalizer. Used for both reference counting
46927 * and mark-and-sweep algorithms. Must never throw an error.
46928 *
46929 * There is no return value. Any return value or error thrown by
46930 * the finalizer is ignored (although errors are debug logged).
46931 *
46932 * Notes:
46933 *
46934 * - The thread used for calling the finalizer is the same as the
46935 * 'thr' argument. This may need to change later.
46936 *
46937 * - The finalizer thread 'top' assertions are there because it is
46938 * critical that strict stack policy is observed (i.e. no cruft
46939 * left on the finalizer stack).
46940 */
46941
46942/* include removed: duk_internal.h */
46943
46944DUK_LOCAL duk_ret_t duk__finalize_helper(duk_context *ctx) {
11fdf7f2
TL
46945 duk_hthread *thr;
46946
7c673cae 46947 DUK_ASSERT(ctx != NULL);
11fdf7f2 46948 thr = (duk_hthread *) ctx;
7c673cae
FG
46949
46950 DUK_DDD(DUK_DDDPRINT("protected finalization helper running"));
46951
46952 /* [... obj] */
46953
46954 /* XXX: Finalizer lookup should traverse the prototype chain (to allow
46955 * inherited finalizers) but should not invoke accessors or proxy object
46956 * behavior. At the moment this lookup will invoke proxy behavior, so
46957 * caller must ensure that this function is not called if the target is
46958 * a Proxy.
46959 */
46960
46961 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_FINALIZER); /* -> [... obj finalizer] */
46962 if (!duk_is_callable(ctx, -1)) {
46963 DUK_DDD(DUK_DDDPRINT("-> no finalizer or finalizer not callable"));
46964 return 0;
46965 }
11fdf7f2
TL
46966 duk_dup(ctx, -2);
46967 duk_push_boolean(ctx, DUK_HEAP_HAS_FINALIZER_NORESCUE(thr->heap));
7c673cae 46968 DUK_DDD(DUK_DDDPRINT("-> finalizer found, calling finalizer"));
11fdf7f2 46969 duk_call(ctx, 2); /* [ ... obj finalizer obj heapDestruct ] -> [ ... obj retval ] */
7c673cae
FG
46970 DUK_DDD(DUK_DDDPRINT("finalizer finished successfully"));
46971 return 0;
46972
46973 /* Note: we rely on duk_safe_call() to fix up the stack for the caller,
46974 * so we don't need to pop stuff here. There is no return value;
46975 * caller determines rescued status based on object refcount.
46976 */
46977}
46978
46979DUK_INTERNAL void duk_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj) {
46980 duk_context *ctx = (duk_context *) thr;
46981 duk_ret_t rc;
46982#ifdef DUK_USE_ASSERTIONS
46983 duk_idx_t entry_top;
46984#endif
46985
46986 DUK_DDD(DUK_DDDPRINT("running object finalizer for object: %p", (void *) obj));
46987
46988 DUK_ASSERT(thr != NULL);
46989 DUK_ASSERT(ctx != NULL);
46990 DUK_ASSERT(obj != NULL);
46991 DUK_ASSERT_VALSTACK_SPACE(thr, 1);
46992
46993#ifdef DUK_USE_ASSERTIONS
46994 entry_top = duk_get_top(ctx);
46995#endif
46996 /*
46997 * Get and call the finalizer. All of this must be wrapped
46998 * in a protected call, because even getting the finalizer
46999 * may trigger an error (getter may throw one, for instance).
47000 */
47001
11fdf7f2
TL
47002 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
47003 if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) obj)) {
47004 DUK_D(DUK_DPRINT("object already finalized, avoid running finalizer twice: %!O", obj));
47005 return;
47006 }
47007 DUK_HEAPHDR_SET_FINALIZED((duk_heaphdr *) obj); /* ensure never re-entered until rescue cycle complete */
47008 if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj)) {
47009 /* This shouldn't happen; call sites should avoid looking up
47010 * _Finalizer "through" a Proxy, but ignore if we come here
47011 * with a Proxy to avoid finalizer re-entry.
47012 */
47013 DUK_D(DUK_DPRINT("object is a proxy, skip finalizer call"));
47014 return;
47015 }
47016
7c673cae
FG
47017 /* XXX: use a NULL error handler for the finalizer call? */
47018
47019 DUK_DDD(DUK_DDDPRINT("-> finalizer found, calling wrapped finalize helper"));
47020 duk_push_hobject(ctx, obj); /* this also increases refcount by one */
47021 rc = duk_safe_call(ctx, duk__finalize_helper, 0 /*nargs*/, 1 /*nrets*/); /* -> [... obj retval/error] */
47022 DUK_ASSERT_TOP(ctx, entry_top + 2); /* duk_safe_call discipline */
47023
47024 if (rc != DUK_EXEC_SUCCESS) {
47025 /* Note: we ask for one return value from duk_safe_call to get this
47026 * error debugging here.
47027 */
47028 DUK_D(DUK_DPRINT("wrapped finalizer call failed for object %p (ignored); error: %!T",
47029 (void *) obj, (duk_tval *) duk_get_tval(ctx, -1)));
47030 }
47031 duk_pop_2(ctx); /* -> [...] */
47032
47033 DUK_ASSERT_TOP(ctx, entry_top);
47034}
7c673cae
FG
47035/*
47036 * Misc support functions
47037 */
47038
47039/* include removed: duk_internal.h */
47040
47041DUK_INTERNAL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *thr, duk_hobject *h, duk_hobject *p, duk_bool_t ignore_loop) {
47042 duk_uint_t sanity;
47043
47044 DUK_ASSERT(thr != NULL);
11fdf7f2
TL
47045
47046 /* False if the object is NULL or the prototype 'p' is NULL.
47047 * In particular, false if both are NULL (don't compare equal).
47048 */
47049 if (h == NULL || p == NULL) {
47050 return 0;
47051 }
7c673cae
FG
47052
47053 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
47054 do {
47055 if (h == p) {
47056 return 1;
47057 }
47058
47059 if (sanity-- == 0) {
47060 if (ignore_loop) {
47061 break;
47062 } else {
11fdf7f2 47063 DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
7c673cae
FG
47064 }
47065 }
47066 h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
47067 } while (h);
47068
47069 return 0;
47070}
47071
11fdf7f2 47072DUK_INTERNAL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p) {
7c673cae
FG
47073#ifdef DUK_USE_REFERENCE_COUNTING
47074 duk_hobject *tmp;
47075
47076 DUK_ASSERT(h);
47077 tmp = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
47078 DUK_HOBJECT_SET_PROTOTYPE(thr->heap, h, p);
47079 DUK_HOBJECT_INCREF_ALLOWNULL(thr, p); /* avoid problems if p == h->prototype */
47080 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
47081#else
47082 DUK_ASSERT(h);
47083 DUK_UNREF(thr);
47084 DUK_HOBJECT_SET_PROTOTYPE(thr->heap, h, p);
47085#endif
47086}
7c673cae
FG
47087/*
47088 * Helpers for creating and querying pc2line debug data, which
47089 * converts a bytecode program counter to a source line number.
47090 *
47091 * The run-time pc2line data is bit-packed, and documented in:
47092 *
47093 * doc/function-objects.rst
47094 */
47095
47096/* include removed: duk_internal.h */
47097
47098#if defined(DUK_USE_PC2LINE)
47099
47100/* Generate pc2line data for an instruction sequence, leaving a buffer on stack top. */
47101DUK_INTERNAL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr *instrs, duk_uint_fast32_t length) {
47102 duk_context *ctx = (duk_context *) thr;
47103 duk_hbuffer_dynamic *h_buf;
47104 duk_bitencoder_ctx be_ctx_alloc;
47105 duk_bitencoder_ctx *be_ctx = &be_ctx_alloc;
47106 duk_uint32_t *hdr;
47107 duk_size_t new_size;
47108 duk_uint_fast32_t num_header_entries;
47109 duk_uint_fast32_t curr_offset;
47110 duk_int_fast32_t curr_line, next_line, diff_line;
47111 duk_uint_fast32_t curr_pc;
47112 duk_uint_fast32_t hdr_index;
47113
47114 DUK_ASSERT(length <= DUK_COMPILER_MAX_BYTECODE_LENGTH);
47115
47116 /* XXX: add proper spare handling to dynamic buffer, to minimize
47117 * reallocs; currently there is no spare at all.
47118 */
47119
47120 num_header_entries = (length + DUK_PC2LINE_SKIP - 1) / DUK_PC2LINE_SKIP;
47121 curr_offset = (duk_uint_fast32_t) (sizeof(duk_uint32_t) + num_header_entries * sizeof(duk_uint32_t) * 2);
47122
47123 duk_push_dynamic_buffer(ctx, (duk_size_t) curr_offset);
47124 h_buf = (duk_hbuffer_dynamic *) duk_get_hbuffer(ctx, -1);
47125 DUK_ASSERT(h_buf != NULL);
47126 DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h_buf) && !DUK_HBUFFER_HAS_EXTERNAL(h_buf));
47127
47128 hdr = (duk_uint32_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h_buf);
47129 DUK_ASSERT(hdr != NULL);
47130 hdr[0] = (duk_uint32_t) length; /* valid pc range is [0, length[ */
47131
47132 curr_pc = 0U;
47133 while (curr_pc < length) {
47134 new_size = (duk_size_t) (curr_offset + DUK_PC2LINE_MAX_DIFF_LENGTH);
47135 duk_hbuffer_resize(thr, h_buf, new_size);
47136
47137 hdr = (duk_uint32_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h_buf);
47138 DUK_ASSERT(hdr != NULL);
47139 DUK_ASSERT(curr_pc < length);
47140 hdr_index = 1 + (curr_pc / DUK_PC2LINE_SKIP) * 2;
47141 curr_line = (duk_int_fast32_t) instrs[curr_pc].line;
47142 hdr[hdr_index + 0] = (duk_uint32_t) curr_line;
47143 hdr[hdr_index + 1] = (duk_uint32_t) curr_offset;
47144
47145#if 0
47146 DUK_DDD(DUK_DDDPRINT("hdr[%ld]: pc=%ld line=%ld offset=%ld",
47147 (long) (curr_pc / DUK_PC2LINE_SKIP),
47148 (long) curr_pc,
47149 (long) hdr[hdr_index + 0],
47150 (long) hdr[hdr_index + 1]));
47151#endif
47152
47153 DUK_MEMZERO(be_ctx, sizeof(*be_ctx));
47154 be_ctx->data = ((duk_uint8_t *) hdr) + curr_offset;
47155 be_ctx->length = (duk_size_t) DUK_PC2LINE_MAX_DIFF_LENGTH;
47156
47157 for (;;) {
47158 curr_pc++;
47159 if ( ((curr_pc % DUK_PC2LINE_SKIP) == 0) || /* end of diff run */
47160 (curr_pc >= length) ) { /* end of bytecode */
47161 break;
47162 }
47163 DUK_ASSERT(curr_pc < length);
47164 next_line = (duk_int32_t) instrs[curr_pc].line;
47165 diff_line = next_line - curr_line;
47166
47167#if 0
47168 DUK_DDD(DUK_DDDPRINT("curr_line=%ld, next_line=%ld -> diff_line=%ld",
47169 (long) curr_line, (long) next_line, (long) diff_line));
47170#endif
47171
47172 if (diff_line == 0) {
47173 /* 0 */
47174 duk_be_encode(be_ctx, 0, 1);
47175 } else if (diff_line >= 1 && diff_line <= 4) {
47176 /* 1 0 <2 bits> */
47177 duk_be_encode(be_ctx, (0x02 << 2) + (diff_line - 1), 4);
47178 } else if (diff_line >= -0x80 && diff_line <= 0x7f) {
47179 /* 1 1 0 <8 bits> */
47180 DUK_ASSERT(diff_line + 0x80 >= 0 && diff_line + 0x80 <= 0xff);
47181 duk_be_encode(be_ctx, (0x06 << 8) + (diff_line + 0x80), 11);
47182 } else {
47183 /* 1 1 1 <32 bits>
47184 * Encode in two parts to avoid bitencode 24-bit limitation
47185 */
47186 duk_be_encode(be_ctx, (0x07 << 16) + ((next_line >> 16) & 0xffffU), 19);
47187 duk_be_encode(be_ctx, next_line & 0xffffU, 16);
47188 }
47189
47190 curr_line = next_line;
47191 }
47192
47193 duk_be_finish(be_ctx);
47194 DUK_ASSERT(!be_ctx->truncated);
47195
47196 /* be_ctx->offset == length of encoded bitstream */
47197 curr_offset += (duk_uint_fast32_t) be_ctx->offset;
47198 }
47199
47200 /* compact */
47201 new_size = (duk_size_t) curr_offset;
47202 duk_hbuffer_resize(thr, h_buf, new_size);
47203
47204 (void) duk_to_fixed_buffer(ctx, -1, NULL);
47205
47206 DUK_DDD(DUK_DDDPRINT("final pc2line data: pc_limit=%ld, length=%ld, %lf bits/opcode --> %!ixT",
47207 (long) length, (long) new_size, (double) new_size * 8.0 / (double) length,
47208 (duk_tval *) duk_get_tval(ctx, -1)));
47209}
47210
47211/* PC is unsigned. If caller does PC arithmetic and gets a negative result,
47212 * it will map to a large PC which is out of bounds and causes a zero to be
47213 * returned.
47214 */
47215DUK_LOCAL duk_uint_fast32_t duk__hobject_pc2line_query_raw(duk_hthread *thr, duk_hbuffer_fixed *buf, duk_uint_fast32_t pc) {
47216 duk_bitdecoder_ctx bd_ctx_alloc;
47217 duk_bitdecoder_ctx *bd_ctx = &bd_ctx_alloc;
47218 duk_uint32_t *hdr;
47219 duk_uint_fast32_t start_offset;
47220 duk_uint_fast32_t pc_limit;
47221 duk_uint_fast32_t hdr_index;
47222 duk_uint_fast32_t pc_base;
47223 duk_uint_fast32_t n;
47224 duk_uint_fast32_t curr_line;
47225
47226 DUK_ASSERT(buf != NULL);
47227 DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) buf) && !DUK_HBUFFER_HAS_EXTERNAL((duk_hbuffer *) buf));
47228 DUK_UNREF(thr);
47229
47230 /*
47231 * Use the index in the header to find the right starting point
47232 */
47233
47234 hdr_index = pc / DUK_PC2LINE_SKIP;
47235 pc_base = hdr_index * DUK_PC2LINE_SKIP;
47236 n = pc - pc_base;
47237
47238 if (DUK_HBUFFER_FIXED_GET_SIZE(buf) <= sizeof(duk_uint32_t)) {
47239 DUK_DD(DUK_DDPRINT("pc2line lookup failed: buffer is smaller than minimal header"));
47240 goto error;
47241 }
47242
47243 hdr = (duk_uint32_t *) (void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, buf);
47244 pc_limit = hdr[0];
47245 if (pc >= pc_limit) {
47246 /* Note: pc is unsigned and cannot be negative */
47247 DUK_DD(DUK_DDPRINT("pc2line lookup failed: pc out of bounds (pc=%ld, limit=%ld)",
47248 (long) pc, (long) pc_limit));
47249 goto error;
47250 }
47251
47252 curr_line = hdr[1 + hdr_index * 2];
47253 start_offset = hdr[1 + hdr_index * 2 + 1];
47254 if ((duk_size_t) start_offset > DUK_HBUFFER_FIXED_GET_SIZE(buf)) {
47255 DUK_DD(DUK_DDPRINT("pc2line lookup failed: start_offset out of bounds (start_offset=%ld, buffer_size=%ld)",
47256 (long) start_offset, (long) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) buf)));
47257 goto error;
47258 }
47259
47260 /*
47261 * Iterate the bitstream (line diffs) until PC is reached
47262 */
47263
47264 DUK_MEMZERO(bd_ctx, sizeof(*bd_ctx));
47265 bd_ctx->data = ((duk_uint8_t *) hdr) + start_offset;
47266 bd_ctx->length = (duk_size_t) (DUK_HBUFFER_FIXED_GET_SIZE(buf) - start_offset);
47267
47268#if 0
47269 DUK_DDD(DUK_DDDPRINT("pc2line lookup: pc=%ld -> hdr_index=%ld, pc_base=%ld, n=%ld, start_offset=%ld",
47270 (long) pc, (long) hdr_index, (long) pc_base, (long) n, (long) start_offset));
47271#endif
47272
47273 while (n > 0) {
47274#if 0
47275 DUK_DDD(DUK_DDDPRINT("lookup: n=%ld, curr_line=%ld", (long) n, (long) curr_line));
47276#endif
47277
47278 if (duk_bd_decode_flag(bd_ctx)) {
47279 if (duk_bd_decode_flag(bd_ctx)) {
47280 if (duk_bd_decode_flag(bd_ctx)) {
47281 /* 1 1 1 <32 bits> */
47282 duk_uint_fast32_t t;
47283 t = duk_bd_decode(bd_ctx, 16); /* workaround: max nbits = 24 now */
47284 t = (t << 16) + duk_bd_decode(bd_ctx, 16);
47285 curr_line = t;
47286 } else {
47287 /* 1 1 0 <8 bits> */
47288 duk_uint_fast32_t t;
47289 t = duk_bd_decode(bd_ctx, 8);
47290 curr_line = curr_line + t - 0x80;
47291 }
47292 } else {
47293 /* 1 0 <2 bits> */
47294 duk_uint_fast32_t t;
47295 t = duk_bd_decode(bd_ctx, 2);
47296 curr_line = curr_line + t + 1;
47297 }
47298 } else {
47299 /* 0: no change */
47300 }
47301
47302 n--;
47303 }
47304
47305 DUK_DDD(DUK_DDDPRINT("pc2line lookup result: pc %ld -> line %ld", (long) pc, (long) curr_line));
47306 return curr_line;
47307
47308 error:
47309 DUK_D(DUK_DPRINT("pc2line conversion failed for pc=%ld", (long) pc));
47310 return 0;
47311}
47312
47313DUK_INTERNAL duk_uint_fast32_t duk_hobject_pc2line_query(duk_context *ctx, duk_idx_t idx_func, duk_uint_fast32_t pc) {
47314 duk_hbuffer_fixed *pc2line;
47315 duk_uint_fast32_t line;
47316
47317 /* XXX: now that pc2line is used by the debugger quite heavily in
47318 * checked execution, this should be optimized to avoid value stack
47319 * and perhaps also implement some form of pc2line caching (see
47320 * future work in debugger.rst).
47321 */
47322
47323 duk_get_prop_stridx(ctx, idx_func, DUK_STRIDX_INT_PC2LINE);
47324 pc2line = (duk_hbuffer_fixed *) duk_get_hbuffer(ctx, -1);
47325 if (pc2line != NULL) {
47326 DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) pc2line) && !DUK_HBUFFER_HAS_EXTERNAL((duk_hbuffer *) pc2line));
47327 line = duk__hobject_pc2line_query_raw((duk_hthread *) ctx, pc2line, (duk_uint_fast32_t) pc);
47328 } else {
47329 line = 0;
47330 }
47331 duk_pop(ctx);
47332
47333 return line;
47334}
47335
47336#endif /* DUK_USE_PC2LINE */
7c673cae
FG
47337/*
47338 * Hobject property set/get functionality.
47339 *
47340 * This is very central functionality for size, performance, and compliance.
47341 * It is also rather intricate; see hobject-algorithms.rst for discussion on
47342 * the algorithms and memory-management.rst for discussion on refcounts and
47343 * side effect issues.
47344 *
47345 * Notes:
47346 *
47347 * - It might be tempting to assert "refcount nonzero" for objects
47348 * being operated on, but that's not always correct: objects with
47349 * a zero refcount may be operated on by the refcount implementation
47350 * (finalization) for instance. Hence, no refcount assertions are made.
47351 *
47352 * - Many operations (memory allocation, identifier operations, etc)
47353 * may cause arbitrary side effects (e.g. through GC and finalization).
47354 * These side effects may invalidate duk_tval pointers which point to
47355 * areas subject to reallocation (like value stack). Heap objects
47356 * themselves have stable pointers. Holding heap object pointers or
47357 * duk_tval copies is not problematic with respect to side effects;
47358 * care must be taken when holding and using argument duk_tval pointers.
47359 *
47360 * - If a finalizer is executed, it may operate on the the same object
47361 * we're currently dealing with. For instance, the finalizer might
47362 * delete a certain property which has already been looked up and
47363 * confirmed to exist. Ideally finalizers would be disabled if GC
47364 * happens during property access. At the moment property table realloc
47365 * disables finalizers, and all DECREFs may cause arbitrary changes so
47366 * handle DECREF carefully.
47367 *
47368 * - The order of operations for a DECREF matters. When DECREF is executed,
47369 * the entire object graph must be consistent; note that a refzero may
47370 * lead to a mark-and-sweep through a refcount finalizer.
47371 */
47372
47373/*
47374 * XXX: array indices are mostly typed as duk_uint32_t here; duk_uarridx_t
47375 * might be more appropriate.
47376 */
47377
47378/*
47379 * XXX: duk_uint_fast32_t should probably be used in many places here.
47380 */
47381
47382/* include removed: duk_internal.h */
47383
47384/*
47385 * Local defines
47386 */
47387
47388#define DUK__NO_ARRAY_INDEX DUK_HSTRING_NO_ARRAY_INDEX
47389
47390/* hash probe sequence */
47391#define DUK__HASH_INITIAL(hash,h_size) DUK_HOBJECT_HASH_INITIAL((hash),(h_size))
47392#define DUK__HASH_PROBE_STEP(hash) DUK_HOBJECT_HASH_PROBE_STEP((hash))
47393
47394/* marker values for hash part */
47395#define DUK__HASH_UNUSED DUK_HOBJECT_HASHIDX_UNUSED
47396#define DUK__HASH_DELETED DUK_HOBJECT_HASHIDX_DELETED
47397
47398/* valstack space that suffices for all local calls, including recursion
47399 * of other than Duktape calls (getters etc)
47400 */
47401#define DUK__VALSTACK_SPACE 10
47402
47403/* valstack space allocated especially for proxy lookup which does a
47404 * recursive property lookup
47405 */
47406#define DUK__VALSTACK_PROXY_LOOKUP 20
47407
47408/*
47409 * Local prototypes
47410 */
47411
7c673cae
FG
47412DUK_LOCAL_DECL duk_bool_t duk__check_arguments_map_for_get(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc);
47413DUK_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);
47414DUK_LOCAL_DECL void duk__check_arguments_map_for_delete(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc);
47415
47416DUK_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);
47417DUK_LOCAL_DECL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hobject *obj);
47418
11fdf7f2
TL
47419DUK_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);
47420DUK_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);
7c673cae
FG
47421DUK_LOCAL duk_uint32_t duk__get_old_array_length(duk_hthread *thr, duk_hobject *obj, duk_propdesc *temp_desc);
47422
47423/*
47424 * Misc helpers
47425 */
47426
47427/* Convert a duk_tval number (caller checks) to a 32-bit index. Returns
47428 * DUK__NO_ARRAY_INDEX if the number is not whole or not a valid array
47429 * index.
47430 */
47431/* XXX: for fastints, could use a variant which assumes a double duk_tval
47432 * (and doesn't need to check for fastint again).
47433 */
47434DUK_LOCAL duk_uint32_t duk__tval_number_to_arr_idx(duk_tval *tv) {
47435 duk_double_t dbl;
47436 duk_uint32_t idx;
47437
47438 DUK_ASSERT(tv != NULL);
47439 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
47440
11fdf7f2
TL
47441 /* -0 is accepted here as index 0 because ToString(-0) == "0" which is
47442 * in canonical form and thus an array index.
47443 */
7c673cae
FG
47444 dbl = DUK_TVAL_GET_NUMBER(tv);
47445 idx = (duk_uint32_t) dbl;
47446 if ((duk_double_t) idx == dbl) {
47447 /* Is whole and within 32 bit range. If the value happens to be 0xFFFFFFFF,
47448 * it's not a valid array index but will then match DUK__NO_ARRAY_INDEX.
47449 */
47450 return idx;
47451 }
47452 return DUK__NO_ARRAY_INDEX;
47453}
47454
47455#if defined(DUK_USE_FASTINT)
47456/* Convert a duk_tval fastint (caller checks) to a 32-bit index. */
47457DUK_LOCAL duk_uint32_t duk__tval_fastint_to_arr_idx(duk_tval *tv) {
47458 duk_int64_t t;
47459
47460 DUK_ASSERT(tv != NULL);
47461 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv));
47462
47463 t = DUK_TVAL_GET_FASTINT(tv);
47464 if ((t & ~0xffffffffULL) != 0) {
47465 /* Catches >0x100000000 and negative values. */
47466 return DUK__NO_ARRAY_INDEX;
47467 }
47468
47469 /* If the value happens to be 0xFFFFFFFF, it's not a valid array index
47470 * but will then match DUK__NO_ARRAY_INDEX.
47471 */
47472 return (duk_uint32_t) t;
47473}
47474#endif /* DUK_USE_FASTINT */
47475
47476/* Push an arbitrary duk_tval to the stack, coerce it to string, and return
47477 * both a duk_hstring pointer and an array index (or DUK__NO_ARRAY_INDEX).
47478 */
47479DUK_LOCAL duk_uint32_t duk__push_tval_to_hstring_arr_idx(duk_context *ctx, duk_tval *tv, duk_hstring **out_h) {
47480 duk_uint32_t arr_idx;
47481 duk_hstring *h;
47482
47483 DUK_ASSERT(ctx != NULL);
47484 DUK_ASSERT(tv != NULL);
47485 DUK_ASSERT(out_h != NULL);
47486
47487 duk_push_tval(ctx, tv);
47488 duk_to_string(ctx, -1);
47489 h = duk_get_hstring(ctx, -1);
47490 DUK_ASSERT(h != NULL);
47491 *out_h = h;
47492
47493 arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(h);
47494 return arr_idx;
47495}
47496
47497/* String is an own (virtual) property of a lightfunc. */
47498DUK_LOCAL duk_bool_t duk__key_is_lightfunc_ownprop(duk_hthread *thr, duk_hstring *key) {
11fdf7f2 47499 DUK_UNREF(thr);
7c673cae
FG
47500 return (key == DUK_HTHREAD_STRING_LENGTH(thr) ||
47501 key == DUK_HTHREAD_STRING_NAME(thr));
47502}
47503
47504/*
47505 * Helpers for managing property storage size
47506 */
47507
47508/* Get default hash part size for a certain entry part size. */
47509#if defined(DUK_USE_HOBJECT_HASH_PART)
47510DUK_LOCAL duk_uint32_t duk__get_default_h_size(duk_uint32_t e_size) {
47511 DUK_ASSERT(e_size <= DUK_HOBJECT_MAX_PROPERTIES);
47512
47513 if (e_size >= DUK_HOBJECT_E_USE_HASH_LIMIT) {
47514 duk_uint32_t res;
47515
47516 /* result: hash_prime(floor(1.2 * e_size)) */
47517 res = duk_util_get_hash_prime(e_size + e_size / DUK_HOBJECT_H_SIZE_DIVISOR);
47518
47519 /* if fails, e_size will be zero = not an issue, except performance-wise */
47520 DUK_ASSERT(res == 0 || res > e_size);
47521 return res;
47522 } else {
47523 return 0;
47524 }
47525}
47526#endif /* USE_PROP_HASH_PART */
47527
47528/* Get minimum entry part growth for a certain size. */
47529DUK_LOCAL duk_uint32_t duk__get_min_grow_e(duk_uint32_t e_size) {
47530 duk_uint32_t res;
47531
47532 DUK_ASSERT(e_size <= DUK_HOBJECT_MAX_PROPERTIES);
47533
47534 res = (e_size + DUK_HOBJECT_E_MIN_GROW_ADD) / DUK_HOBJECT_E_MIN_GROW_DIVISOR;
47535 DUK_ASSERT(res >= 1); /* important for callers */
47536 return res;
47537}
47538
47539/* Get minimum array part growth for a certain size. */
47540DUK_LOCAL duk_uint32_t duk__get_min_grow_a(duk_uint32_t a_size) {
47541 duk_uint32_t res;
47542
47543 DUK_ASSERT((duk_size_t) a_size <= DUK_HOBJECT_MAX_PROPERTIES);
47544
47545 res = (a_size + DUK_HOBJECT_A_MIN_GROW_ADD) / DUK_HOBJECT_A_MIN_GROW_DIVISOR;
47546 DUK_ASSERT(res >= 1); /* important for callers */
47547 return res;
47548}
47549
47550/* Count actually used entry part entries (non-NULL keys). */
47551DUK_LOCAL duk_uint32_t duk__count_used_e_keys(duk_hthread *thr, duk_hobject *obj) {
47552 duk_uint_fast32_t i;
47553 duk_uint_fast32_t n = 0;
47554 duk_hstring **e;
47555
47556 DUK_ASSERT(obj != NULL);
47557 DUK_UNREF(thr);
47558
47559 e = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, obj);
47560 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
47561 if (*e++) {
47562 n++;
47563 }
47564 }
47565 return (duk_uint32_t) n;
47566}
47567
47568/* Count actually used array part entries and array minimum size.
47569 * NOTE: 'out_min_size' can be computed much faster by starting from the
47570 * end and breaking out early when finding first used entry, but this is
47571 * not needed now.
47572 */
47573DUK_LOCAL void duk__compute_a_stats(duk_hthread *thr, duk_hobject *obj, duk_uint32_t *out_used, duk_uint32_t *out_min_size) {
47574 duk_uint_fast32_t i;
47575 duk_uint_fast32_t used = 0;
47576 duk_uint_fast32_t highest_idx = (duk_uint_fast32_t) -1; /* see below */
47577 duk_tval *a;
47578
47579 DUK_ASSERT(obj != NULL);
47580 DUK_ASSERT(out_used != NULL);
47581 DUK_ASSERT(out_min_size != NULL);
47582 DUK_UNREF(thr);
47583
47584 a = DUK_HOBJECT_A_GET_BASE(thr->heap, obj);
47585 for (i = 0; i < DUK_HOBJECT_GET_ASIZE(obj); i++) {
47586 duk_tval *tv = a++;
11fdf7f2 47587 if (!DUK_TVAL_IS_UNUSED(tv)) {
7c673cae
FG
47588 used++;
47589 highest_idx = i;
47590 }
47591 }
47592
47593 /* Initial value for highest_idx is -1 coerced to unsigned. This
47594 * is a bit odd, but (highest_idx + 1) will then wrap to 0 below
47595 * for out_min_size as intended.
47596 */
47597
47598 *out_used = used;
47599 *out_min_size = highest_idx + 1; /* 0 if no used entries */
47600}
47601
47602/* Check array density and indicate whether or not the array part should be abandoned. */
47603DUK_LOCAL duk_bool_t duk__abandon_array_density_check(duk_uint32_t a_used, duk_uint32_t a_size) {
47604 /*
47605 * Array abandon check; abandon if:
47606 *
47607 * new_used / new_size < limit
47608 * new_used < limit * new_size || limit is 3 bits fixed point
47609 * new_used < limit' / 8 * new_size || *8
47610 * 8*new_used < limit' * new_size || :8
47611 * new_used < limit' * (new_size / 8)
47612 *
47613 * Here, new_used = a_used, new_size = a_size.
47614 *
47615 * Note: some callers use approximate values for a_used and/or a_size
47616 * (e.g. dropping a '+1' term). This doesn't affect the usefulness
47617 * of the check, but may confuse debugging.
47618 */
47619
47620 return (a_used < DUK_HOBJECT_A_ABANDON_LIMIT * (a_size >> 3));
47621}
47622
47623/* Fast check for extending array: check whether or not a slow density check is required. */
47624DUK_LOCAL duk_bool_t duk__abandon_array_slow_check_required(duk_uint32_t arr_idx, duk_uint32_t old_size) {
47625 /*
47626 * In a fast check we assume old_size equals old_used (i.e., existing
47627 * array is fully dense).
47628 *
47629 * Slow check if:
47630 *
47631 * (new_size - old_size) / old_size > limit
47632 * new_size - old_size > limit * old_size
47633 * new_size > (1 + limit) * old_size || limit' is 3 bits fixed point
47634 * new_size > (1 + (limit' / 8)) * old_size || * 8
47635 * 8 * new_size > (8 + limit') * old_size || : 8
47636 * new_size > (8 + limit') * (old_size / 8)
47637 * new_size > limit'' * (old_size / 8) || limit'' = 9 -> max 25% increase
47638 * arr_idx + 1 > limit'' * (old_size / 8)
47639 *
47640 * This check doesn't work well for small values, so old_size is rounded
47641 * up for the check (and the '+ 1' of arr_idx can be ignored in practice):
47642 *
47643 * arr_idx > limit'' * ((old_size + 7) / 8)
47644 */
47645
47646 return (arr_idx > DUK_HOBJECT_A_FAST_RESIZE_LIMIT * ((old_size + 7) >> 3));
47647}
47648
47649/*
47650 * Proxy helpers
47651 */
47652
47653#if defined(DUK_USE_ES6_PROXY)
47654DUK_INTERNAL duk_bool_t duk_hobject_proxy_check(duk_hthread *thr, duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler) {
47655 duk_tval *tv_target;
47656 duk_tval *tv_handler;
47657 duk_hobject *h_target;
47658 duk_hobject *h_handler;
47659
47660 DUK_ASSERT(thr != NULL);
47661 DUK_ASSERT(obj != NULL);
47662 DUK_ASSERT(out_target != NULL);
47663 DUK_ASSERT(out_handler != NULL);
47664
47665 /* Caller doesn't need to check exotic proxy behavior (but does so for
47666 * some fast paths).
47667 */
47668 if (DUK_LIKELY(!DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
47669 return 0;
47670 }
47671
47672 tv_handler = duk_hobject_find_existing_entry_tval_ptr(thr->heap, obj, DUK_HTHREAD_STRING_INT_HANDLER(thr));
47673 if (!tv_handler) {
11fdf7f2 47674 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REVOKED);
7c673cae
FG
47675 return 0;
47676 }
47677 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_handler));
47678 h_handler = DUK_TVAL_GET_OBJECT(tv_handler);
47679 DUK_ASSERT(h_handler != NULL);
47680 *out_handler = h_handler;
47681 tv_handler = NULL; /* avoid issues with relocation */
47682
47683 tv_target = duk_hobject_find_existing_entry_tval_ptr(thr->heap, obj, DUK_HTHREAD_STRING_INT_TARGET(thr));
47684 if (!tv_target) {
11fdf7f2 47685 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REVOKED);
7c673cae
FG
47686 return 0;
47687 }
47688 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_target));
47689 h_target = DUK_TVAL_GET_OBJECT(tv_target);
47690 DUK_ASSERT(h_target != NULL);
47691 *out_target = h_target;
47692 tv_target = NULL; /* avoid issues with relocation */
47693
47694 return 1;
47695}
47696#endif /* DUK_USE_ES6_PROXY */
47697
47698/* Get Proxy target object. If the argument is not a Proxy, return it as is.
47699 * If a Proxy is revoked, an error is thrown.
47700 */
47701#if defined(DUK_USE_ES6_PROXY)
47702DUK_INTERNAL duk_hobject *duk_hobject_resolve_proxy_target(duk_hthread *thr, duk_hobject *obj) {
47703 duk_hobject *h_target;
47704 duk_hobject *h_handler;
47705
47706 DUK_ASSERT(thr != NULL);
47707 DUK_ASSERT(obj != NULL);
47708
47709 /* Resolve Proxy targets until Proxy chain ends. No explicit check for
47710 * a Proxy loop: user code cannot create such a loop without tweaking
47711 * internal properties directly.
47712 */
47713
47714 while (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
47715 if (duk_hobject_proxy_check(thr, obj, &h_target, &h_handler)) {
47716 DUK_ASSERT(h_target != NULL);
47717 obj = h_target;
47718 } else {
47719 break;
47720 }
47721 }
47722
47723 DUK_ASSERT(obj != NULL);
47724 return obj;
47725}
47726#endif /* DUK_USE_ES6_PROXY */
47727
47728#if defined(DUK_USE_ES6_PROXY)
47729DUK_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) {
47730 duk_context *ctx = (duk_context *) thr;
47731 duk_hobject *h_handler;
47732
47733 DUK_ASSERT(thr != NULL);
47734 DUK_ASSERT(obj != NULL);
47735 DUK_ASSERT(tv_key != NULL);
47736 DUK_ASSERT(out_target != NULL);
47737
47738 if (!duk_hobject_proxy_check(thr, obj, out_target, &h_handler)) {
47739 return 0;
47740 }
47741 DUK_ASSERT(*out_target != NULL);
47742 DUK_ASSERT(h_handler != NULL);
47743
47744 /* XXX: At the moment Duktape accesses internal keys like _Finalizer using a
47745 * normal property set/get which would allow a proxy handler to interfere with
47746 * such behavior and to get access to internal key strings. This is not a problem
47747 * as such because internal key strings can be created in other ways too (e.g.
47748 * through buffers). The best fix is to change Duktape internal lookups to
47749 * skip proxy behavior. Until that, internal property accesses bypass the
47750 * proxy and are applied to the target (as if the handler did not exist).
47751 * This has some side effects, see test-bi-proxy-internal-keys.js.
47752 */
47753
47754 if (DUK_TVAL_IS_STRING(tv_key)) {
47755 duk_hstring *h_key = (duk_hstring *) DUK_TVAL_GET_STRING(tv_key);
47756 DUK_ASSERT(h_key != NULL);
47757 if (DUK_HSTRING_HAS_INTERNAL(h_key)) {
47758 DUK_DDD(DUK_DDDPRINT("internal key, skip proxy handler and apply to target"));
47759 return 0;
47760 }
47761 }
47762
47763 /* The handler is looked up with a normal property lookup; it may be an
47764 * accessor or the handler object itself may be a proxy object. If the
47765 * handler is a proxy, we need to extend the valstack as we make a
47766 * recursive proxy check without a function call in between (in fact
47767 * there is no limit to the potential recursion here).
47768 *
47769 * (For sanity, proxy creation rejects another proxy object as either
47770 * the handler or the target at the moment so recursive proxy cases
47771 * are not realized now.)
47772 */
47773
47774 /* XXX: C recursion limit if proxies are allowed as handler/target values */
47775
47776 duk_require_stack(ctx, DUK__VALSTACK_PROXY_LOOKUP);
47777 duk_push_hobject(ctx, h_handler);
47778 if (duk_get_prop_stridx(ctx, -1, stridx_trap)) {
47779 /* -> [ ... handler trap ] */
47780 duk_insert(ctx, -2); /* -> [ ... trap handler ] */
47781
47782 /* stack prepped for func call: [ ... trap handler ] */
47783 return 1;
47784 } else {
47785 duk_pop_2(ctx);
47786 return 0;
47787 }
47788}
47789#endif /* DUK_USE_ES6_PROXY */
47790
47791/*
47792 * Reallocate property allocation, moving properties to the new allocation.
47793 *
47794 * Includes key compaction, rehashing, and can also optionally abandoning
47795 * the array part, 'migrating' array entries into the beginning of the
47796 * new entry part. Arguments are not validated here, so e.g. new_h_size
47797 * MUST be a valid prime.
47798 *
47799 * There is no support for in-place reallocation or just compacting keys
47800 * without resizing the property allocation. This is intentional to keep
47801 * code size minimal.
47802 *
47803 * The implementation is relatively straightforward, except for the array
47804 * abandonment process. Array abandonment requires that new string keys
47805 * are interned, which may trigger GC. All keys interned so far must be
47806 * reachable for GC at all times; valstack is used for that now.
47807 *
47808 * Also, a GC triggered during this reallocation process must not interfere
47809 * with the object being resized. This is currently controlled by using
47810 * heap->mark_and_sweep_base_flags to indicate that no finalizers will be
47811 * executed (as they can affect ANY object) and no objects are compacted
47812 * (it would suffice to protect this particular object only, though).
47813 *
47814 * Note: a non-checked variant would be nice but is a bit tricky to
47815 * implement for the array abandonment process. It's easy for
47816 * everything else.
47817 *
47818 * Note: because we need to potentially resize the valstack (as part
47819 * of abandoning the array part), any tval pointers to the valstack
47820 * will become invalid after this call.
47821 */
47822
47823DUK_LOCAL
47824void duk__realloc_props(duk_hthread *thr,
47825 duk_hobject *obj,
47826 duk_uint32_t new_e_size,
47827 duk_uint32_t new_a_size,
47828 duk_uint32_t new_h_size,
47829 duk_bool_t abandon_array) {
47830 duk_context *ctx = (duk_context *) thr;
47831#ifdef DUK_USE_MARK_AND_SWEEP
47832 duk_small_uint_t prev_mark_and_sweep_base_flags;
47833#endif
47834 duk_uint32_t new_alloc_size;
47835 duk_uint32_t new_e_size_adjusted;
47836 duk_uint8_t *new_p;
47837 duk_hstring **new_e_k;
47838 duk_propvalue *new_e_pv;
47839 duk_uint8_t *new_e_f;
47840 duk_tval *new_a;
47841 duk_uint32_t *new_h;
47842 duk_uint32_t new_e_next;
47843 duk_uint_fast32_t i;
47844
47845 DUK_ASSERT(thr != NULL);
47846 DUK_ASSERT(ctx != NULL);
47847 DUK_ASSERT(obj != NULL);
47848 DUK_ASSERT(!abandon_array || new_a_size == 0); /* if abandon_array, new_a_size must be 0 */
47849 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL || (DUK_HOBJECT_GET_ESIZE(obj) == 0 && DUK_HOBJECT_GET_ASIZE(obj) == 0));
47850 DUK_ASSERT(new_h_size == 0 || new_h_size >= new_e_size); /* required to guarantee success of rehashing,
47851 * intentionally use unadjusted new_e_size
47852 */
11fdf7f2 47853 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
7c673cae
FG
47854 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
47855
47856 /*
47857 * Pre resize assertions.
47858 */
47859
47860#ifdef DUK_USE_ASSERTIONS
47861 /* XXX: pre-checks (such as no duplicate keys) */
47862#endif
47863
47864 /*
47865 * For property layout 1, tweak e_size to ensure that the whole entry
47866 * part (key + val + flags) is a suitable multiple for alignment
47867 * (platform specific).
47868 *
47869 * Property layout 2 does not require this tweaking and is preferred
47870 * on low RAM platforms requiring alignment.
47871 */
47872
47873#if defined(DUK_USE_HOBJECT_LAYOUT_2) || defined(DUK_USE_HOBJECT_LAYOUT_3)
47874 DUK_DDD(DUK_DDDPRINT("using layout 2 or 3, no need to pad e_size: %ld", (long) new_e_size));
47875 new_e_size_adjusted = new_e_size;
47876#elif defined(DUK_USE_HOBJECT_LAYOUT_1) && (DUK_HOBJECT_ALIGN_TARGET == 1)
47877 DUK_DDD(DUK_DDDPRINT("using layout 1, but no need to pad e_size: %ld", (long) new_e_size));
47878 new_e_size_adjusted = new_e_size;
47879#elif defined(DUK_USE_HOBJECT_LAYOUT_1) && ((DUK_HOBJECT_ALIGN_TARGET == 4) || (DUK_HOBJECT_ALIGN_TARGET == 8))
47880 new_e_size_adjusted = (new_e_size + DUK_HOBJECT_ALIGN_TARGET - 1) & (~(DUK_HOBJECT_ALIGN_TARGET - 1));
47881 DUK_DDD(DUK_DDDPRINT("using layout 1, and alignment target is %ld, adjusted e_size: %ld -> %ld",
47882 (long) DUK_HOBJECT_ALIGN_TARGET, (long) new_e_size, (long) new_e_size_adjusted));
47883 DUK_ASSERT(new_e_size_adjusted >= new_e_size);
47884#else
47885#error invalid hobject layout defines
47886#endif
47887
47888 /*
47889 * Debug logging after adjustment.
47890 */
47891
47892 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 "
47893 "{e_size=%ld,a_size=%ld,h_size=%ld}, abandon_array=%ld, unadjusted new_e_size=%ld",
47894 (void *) obj,
47895 (long) DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj),
47896 DUK_HOBJECT_GET_ASIZE(obj),
47897 DUK_HOBJECT_GET_HSIZE(obj)),
47898 (long) DUK_HOBJECT_P_COMPUTE_SIZE(new_e_size_adjusted, new_a_size, new_h_size),
47899 (void *) DUK_HOBJECT_GET_PROPS(thr->heap, obj),
47900 (long) DUK_HOBJECT_GET_ESIZE(obj),
47901 (long) DUK_HOBJECT_GET_ENEXT(obj),
47902 (long) DUK_HOBJECT_GET_ASIZE(obj),
47903 (long) DUK_HOBJECT_GET_HSIZE(obj),
47904 (long) new_e_size_adjusted,
47905 (long) new_a_size,
47906 (long) new_h_size,
47907 (long) abandon_array,
47908 (long) new_e_size));
47909
47910 /*
47911 * Property count check. This is the only point where we ensure that
47912 * we don't get more (allocated) property space that we can handle.
47913 * There aren't hard limits as such, but some algorithms fail (e.g.
47914 * finding next higher prime, selecting hash part size) if we get too
47915 * close to the 4G property limit.
47916 *
47917 * Since this works based on allocation size (not actually used size),
47918 * the limit is a bit approximate but good enough in practice.
47919 */
47920
47921 if (new_e_size_adjusted + new_a_size > DUK_HOBJECT_MAX_PROPERTIES) {
11fdf7f2 47922 DUK_ERROR_ALLOC_DEFMSG(thr);
7c673cae
FG
47923 }
47924
47925 /*
47926 * Compute new alloc size and alloc new area.
47927 *
47928 * The new area is allocated as a dynamic buffer and placed into the
47929 * valstack for reachability. The actual buffer is then detached at
47930 * the end.
47931 *
47932 * Note: heap_mark_and_sweep_base_flags are altered here to ensure
47933 * no-one touches this object while we're resizing and rehashing it.
47934 * The flags must be reset on every exit path after it. Finalizers
47935 * and compaction is prevented currently for all objects while it
47936 * would be enough to restrict it only for the current object.
47937 */
47938
47939#ifdef DUK_USE_MARK_AND_SWEEP
47940 prev_mark_and_sweep_base_flags = thr->heap->mark_and_sweep_base_flags;
47941 thr->heap->mark_and_sweep_base_flags |=
47942 DUK_MS_FLAG_NO_FINALIZERS | /* avoid attempts to add/remove object keys */
47943 DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid attempt to compact the current object */
47944#endif
47945
47946 new_alloc_size = DUK_HOBJECT_P_COMPUTE_SIZE(new_e_size_adjusted, new_a_size, new_h_size);
47947 DUK_DDD(DUK_DDDPRINT("new hobject allocation size is %ld", (long) new_alloc_size));
11fdf7f2
TL
47948 new_e_next = 0;
47949 new_e_k = NULL;
7c673cae
FG
47950 if (new_alloc_size == 0) {
47951 /* for zero size, don't push anything on valstack */
47952 DUK_ASSERT(new_e_size_adjusted == 0);
47953 DUK_ASSERT(new_a_size == 0);
47954 DUK_ASSERT(new_h_size == 0);
47955 new_p = NULL;
47956 } else {
47957 /* This may trigger mark-and-sweep with arbitrary side effects,
47958 * including an attempted resize of the object we're resizing,
47959 * executing a finalizer which may add or remove properties of
47960 * the object we're resizing etc.
47961 */
47962
11fdf7f2
TL
47963#if 0 /* XXX: inject test */
47964 if (1) {
47965 goto alloc_failed;
47966 }
47967#endif
47968 new_p = (duk_uint8_t *) DUK_ALLOC(thr->heap, new_alloc_size);
47969 if (new_p == NULL) {
47970 /* NULL always indicates alloc failure because
47971 * new_alloc_size > 0.
47972 */
47973 goto alloc_failed;
47974 }
7c673cae
FG
47975 }
47976
47977 /* Set up pointers to the new property area: this is hidden behind a macro
47978 * because it is memory layout specific.
47979 */
47980 DUK_HOBJECT_P_SET_REALLOC_PTRS(new_p, new_e_k, new_e_pv, new_e_f, new_a, new_h,
47981 new_e_size_adjusted, new_a_size, new_h_size);
47982 DUK_UNREF(new_h); /* happens when hash part dropped */
7c673cae
FG
47983
47984 /* if new_p == NULL, all of these pointers are NULL */
47985 DUK_ASSERT((new_p != NULL) ||
47986 (new_e_k == NULL && new_e_pv == NULL && new_e_f == NULL &&
47987 new_a == NULL && new_h == NULL));
47988
47989 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",
47990 (long) new_alloc_size, (void *) new_e_k, (void *) new_e_pv, (void *) new_e_f,
47991 (void *) new_a, (void *) new_h));
47992
47993 /*
47994 * Migrate array to start of entries if requested.
47995 *
47996 * Note: from an enumeration perspective the order of entry keys matters.
47997 * Array keys should appear wherever they appeared before the array abandon
47998 * operation.
47999 */
48000
48001 if (abandon_array) {
48002 /*
48003 * Note: assuming new_a_size == 0, and that entry part contains
48004 * no conflicting keys, refcounts do not need to be adjusted for
48005 * the values, as they remain exactly the same.
48006 *
48007 * The keys, however, need to be interned, incref'd, and be
48008 * reachable for GC. Any intern attempt may trigger a GC and
48009 * claim any non-reachable strings, so every key must be reachable
48010 * at all times.
48011 *
48012 * A longjmp must not occur here, as the new_p allocation would
48013 * be freed without these keys being decref'd, hence the messy
48014 * decref handling if intern fails.
48015 */
48016 DUK_ASSERT(new_a_size == 0);
48017
48018 for (i = 0; i < DUK_HOBJECT_GET_ASIZE(obj); i++) {
48019 duk_tval *tv1;
48020 duk_tval *tv2;
48021 duk_hstring *key;
48022
48023 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
48024
48025 tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i);
11fdf7f2 48026 if (DUK_TVAL_IS_UNUSED(tv1)) {
7c673cae
FG
48027 continue;
48028 }
48029
48030 DUK_ASSERT(new_p != NULL && new_e_k != NULL &&
48031 new_e_pv != NULL && new_e_f != NULL);
48032
48033 /*
48034 * Intern key via the valstack to ensure reachability behaves
48035 * properly. We must avoid longjmp's here so use non-checked
48036 * primitives.
48037 *
48038 * Note: duk_check_stack() potentially reallocs the valstack,
48039 * invalidating any duk_tval pointers to valstack. Callers
48040 * must be careful.
48041 */
48042
48043 /* never shrinks; auto-adds DUK_VALSTACK_INTERNAL_EXTRA, which is generous */
48044 if (!duk_check_stack(ctx, 1)) {
48045 goto abandon_error;
48046 }
48047 DUK_ASSERT_VALSTACK_SPACE(thr, 1);
48048 key = duk_heap_string_intern_u32(thr->heap, i);
48049 if (!key) {
48050 goto abandon_error;
48051 }
48052 duk_push_hstring(ctx, key); /* keep key reachable for GC etc; guaranteed not to fail */
48053
48054 /* key is now reachable in the valstack */
48055
48056 DUK_HSTRING_INCREF(thr, key); /* second incref for the entry reference */
48057 new_e_k[new_e_next] = key;
48058 tv2 = &new_e_pv[new_e_next].v; /* array entries are all plain values */
48059 DUK_TVAL_SET_TVAL(tv2, tv1);
48060 new_e_f[new_e_next] = DUK_PROPDESC_FLAG_WRITABLE |
48061 DUK_PROPDESC_FLAG_ENUMERABLE |
48062 DUK_PROPDESC_FLAG_CONFIGURABLE;
48063 new_e_next++;
48064
48065 /* Note: new_e_next matches pushed temp key count, and nothing can
48066 * fail above between the push and this point.
48067 */
48068 }
48069
48070 DUK_DDD(DUK_DDDPRINT("abandon array: pop %ld key temps from valstack", (long) new_e_next));
48071 duk_pop_n(ctx, new_e_next);
48072 }
48073
48074 /*
48075 * Copy keys and values in the entry part (compacting them at the same time).
48076 */
48077
48078 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
48079 duk_hstring *key;
48080
48081 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
48082
48083 key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i);
48084 if (!key) {
48085 continue;
48086 }
48087
48088 DUK_ASSERT(new_p != NULL && new_e_k != NULL &&
48089 new_e_pv != NULL && new_e_f != NULL);
48090
48091 new_e_k[new_e_next] = key;
48092 new_e_pv[new_e_next] = DUK_HOBJECT_E_GET_VALUE(thr->heap, obj, i);
48093 new_e_f[new_e_next] = DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, i);
48094 new_e_next++;
48095 }
48096 /* the entries [new_e_next, new_e_size_adjusted[ are left uninitialized on purpose (ok, not gc reachable) */
48097
48098 /*
48099 * Copy array elements to new array part.
48100 */
48101
48102 if (new_a_size > DUK_HOBJECT_GET_ASIZE(obj)) {
48103 /* copy existing entries as is */
48104 DUK_ASSERT(new_p != NULL && new_a != NULL);
48105 if (DUK_HOBJECT_GET_ASIZE(obj) > 0) {
48106 /* Avoid zero copy with an invalid pointer. If obj->p is NULL,
48107 * the 'new_a' pointer will be invalid which is not allowed even
48108 * when copy size is zero.
48109 */
48110 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
48111 DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) > 0);
48112 DUK_MEMCPY((void *) new_a, (void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj), sizeof(duk_tval) * DUK_HOBJECT_GET_ASIZE(obj));
48113 }
48114
48115 /* fill new entries with -unused- (required, gc reachable) */
48116 for (i = DUK_HOBJECT_GET_ASIZE(obj); i < new_a_size; i++) {
48117 duk_tval *tv = &new_a[i];
11fdf7f2 48118 DUK_TVAL_SET_UNUSED(tv);
7c673cae
FG
48119 }
48120 } else {
48121#ifdef DUK_USE_ASSERTIONS
48122 /* caller must have decref'd values above new_a_size (if that is necessary) */
48123 if (!abandon_array) {
48124 for (i = new_a_size; i < DUK_HOBJECT_GET_ASIZE(obj); i++) {
48125 duk_tval *tv;
48126 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i);
48127
48128 /* current assertion is quite strong: decref's and set to unused */
11fdf7f2 48129 DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv));
7c673cae
FG
48130 }
48131 }
48132#endif
48133 if (new_a_size > 0) {
48134 /* Avoid zero copy with an invalid pointer. If obj->p is NULL,
48135 * the 'new_a' pointer will be invalid which is not allowed even
48136 * when copy size is zero.
48137 */
48138 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
48139 DUK_ASSERT(new_a_size > 0);
48140 DUK_MEMCPY((void *) new_a, (void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj), sizeof(duk_tval) * new_a_size);
48141 }
48142 }
48143
48144 /*
48145 * Rebuild the hash part always from scratch (guaranteed to finish).
48146 *
48147 * Any resize of hash part requires rehashing. In addition, by rehashing
48148 * get rid of any elements marked deleted (DUK__HASH_DELETED) which is critical
48149 * to ensuring the hash part never fills up.
48150 */
48151
48152#if defined(DUK_USE_HOBJECT_HASH_PART)
48153 if (DUK_UNLIKELY(new_h_size > 0)) {
48154 DUK_ASSERT(new_h != NULL);
48155
48156 /* fill new_h with u32 0xff = UNUSED */
48157 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
48158 DUK_ASSERT(new_h_size > 0);
48159 DUK_MEMSET(new_h, 0xff, sizeof(duk_uint32_t) * new_h_size);
48160
48161 DUK_ASSERT(new_e_next <= new_h_size); /* equality not actually possible */
48162 for (i = 0; i < new_e_next; i++) {
48163 duk_hstring *key = new_e_k[i];
48164 duk_uint32_t j, step;
48165
48166 DUK_ASSERT(key != NULL);
48167 j = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), new_h_size);
48168 step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key));
48169
48170 for (;;) {
48171 DUK_ASSERT(new_h[j] != DUK__HASH_DELETED); /* should never happen */
48172 if (new_h[j] == DUK__HASH_UNUSED) {
48173 DUK_DDD(DUK_DDDPRINT("rebuild hit %ld -> %ld", (long) j, (long) i));
48174 new_h[j] = i;
48175 break;
48176 }
48177 DUK_DDD(DUK_DDDPRINT("rebuild miss %ld, step %ld", (long) j, (long) step));
48178 j = (j + step) % new_h_size;
48179
48180 /* guaranteed to finish */
48181 DUK_ASSERT(j != (duk_uint32_t) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), new_h_size));
48182 }
48183 }
48184 } else {
48185 DUK_DDD(DUK_DDDPRINT("no hash part, no rehash"));
48186 }
48187#endif /* DUK_USE_HOBJECT_HASH_PART */
48188
48189 /*
48190 * Nice debug log.
48191 */
48192
48193 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 "
48194 "{p=%p,e_size=%ld,e_next=%ld,a_size=%ld,h_size=%ld}, abandon_array=%ld, unadjusted new_e_size=%ld",
48195 (void *) obj,
48196 (long) DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj),
48197 DUK_HOBJECT_GET_ASIZE(obj),
48198 DUK_HOBJECT_GET_HSIZE(obj)),
48199 (long) new_alloc_size,
48200 (void *) DUK_HOBJECT_GET_PROPS(thr->heap, obj),
48201 (long) DUK_HOBJECT_GET_ESIZE(obj),
48202 (long) DUK_HOBJECT_GET_ENEXT(obj),
48203 (long) DUK_HOBJECT_GET_ASIZE(obj),
48204 (long) DUK_HOBJECT_GET_HSIZE(obj),
48205 (void *) new_p,
48206 (long) new_e_size_adjusted,
48207 (long) new_e_next,
48208 (long) new_a_size,
48209 (long) new_h_size,
48210 (long) abandon_array,
48211 (long) new_e_size));
48212
48213 /*
48214 * All done, switch properties ('p') allocation to new one.
48215 */
48216
48217 DUK_FREE(thr->heap, DUK_HOBJECT_GET_PROPS(thr->heap, obj)); /* NULL obj->p is OK */
48218 DUK_HOBJECT_SET_PROPS(thr->heap, obj, new_p);
48219 DUK_HOBJECT_SET_ESIZE(obj, new_e_size_adjusted);
48220 DUK_HOBJECT_SET_ENEXT(obj, new_e_next);
48221 DUK_HOBJECT_SET_ASIZE(obj, new_a_size);
48222 DUK_HOBJECT_SET_HSIZE(obj, new_h_size);
48223
7c673cae
FG
48224 /* clear array part flag only after switching */
48225 if (abandon_array) {
48226 DUK_HOBJECT_CLEAR_ARRAY_PART(obj);
48227 }
48228
48229 DUK_DDD(DUK_DDDPRINT("resize result: %!O", (duk_heaphdr *) obj));
48230
48231#ifdef DUK_USE_MARK_AND_SWEEP
48232 thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
48233#endif
48234
48235 /*
48236 * Post resize assertions.
48237 */
48238
48239#ifdef DUK_USE_ASSERTIONS
48240 /* XXX: post-checks (such as no duplicate keys) */
48241#endif
48242 return;
48243
48244 /*
48245 * Abandon array failed, need to decref keys already inserted
48246 * into the beginning of new_e_k before unwinding valstack.
48247 */
48248
48249 abandon_error:
11fdf7f2
TL
48250 alloc_failed:
48251 DUK_D(DUK_DPRINT("object property table resize failed"));
48252
7c673cae
FG
48253 i = new_e_next;
48254 while (i > 0) {
48255 i--;
48256 DUK_ASSERT(new_e_k != NULL);
48257 DUK_ASSERT(new_e_k[i] != NULL);
11fdf7f2 48258 DUK_HSTRING_DECREF(thr, new_e_k[i]); /* side effects */
7c673cae
FG
48259 }
48260
11fdf7f2
TL
48261 DUK_FREE(thr->heap, new_p); /* OK for NULL. */
48262
7c673cae
FG
48263#ifdef DUK_USE_MARK_AND_SWEEP
48264 thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
48265#endif
48266
11fdf7f2 48267 DUK_ERROR_ALLOC_DEFMSG(thr);
7c673cae
FG
48268}
48269
48270/*
48271 * Helpers to resize properties allocation on specific needs.
48272 */
48273
48274/* Grow entry part allocation for one additional entry. */
48275DUK_LOCAL void duk__grow_props_for_new_entry_item(duk_hthread *thr, duk_hobject *obj) {
48276 duk_uint32_t old_e_used; /* actually used, non-NULL entries */
48277 duk_uint32_t new_e_size;
48278 duk_uint32_t new_a_size;
48279 duk_uint32_t new_h_size;
48280
48281 DUK_ASSERT(thr != NULL);
48282 DUK_ASSERT(obj != NULL);
48283
48284 /* Duktape 0.11.0 and prior tried to optimize the resize by not
48285 * counting the number of actually used keys prior to the resize.
48286 * This worked mostly well but also caused weird leak-like behavior
48287 * as in: test-bug-object-prop-alloc-unbounded.js. So, now we count
48288 * the keys explicitly to compute the new entry part size.
48289 */
48290
48291 old_e_used = duk__count_used_e_keys(thr, obj);
48292 new_e_size = old_e_used + duk__get_min_grow_e(old_e_used);
48293#if defined(DUK_USE_HOBJECT_HASH_PART)
48294 new_h_size = duk__get_default_h_size(new_e_size);
48295#else
48296 new_h_size = 0;
48297#endif
48298 new_a_size = DUK_HOBJECT_GET_ASIZE(obj);
48299 DUK_ASSERT(new_e_size >= old_e_used + 1); /* duk__get_min_grow_e() is always >= 1 */
48300
48301 duk__realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0);
48302}
48303
48304/* Grow array part for a new highest array index. */
48305DUK_LOCAL void duk__grow_props_for_array_item(duk_hthread *thr, duk_hobject *obj, duk_uint32_t highest_arr_idx) {
48306 duk_uint32_t new_e_size;
48307 duk_uint32_t new_a_size;
48308 duk_uint32_t new_h_size;
48309
48310 DUK_ASSERT(thr != NULL);
48311 DUK_ASSERT(obj != NULL);
48312 DUK_ASSERT(highest_arr_idx >= DUK_HOBJECT_GET_ASIZE(obj));
48313
48314 /* minimum new length is highest_arr_idx + 1 */
48315
48316 new_e_size = DUK_HOBJECT_GET_ESIZE(obj);
48317 new_h_size = DUK_HOBJECT_GET_HSIZE(obj);
48318 new_a_size = highest_arr_idx + duk__get_min_grow_a(highest_arr_idx);
48319 DUK_ASSERT(new_a_size >= highest_arr_idx + 1); /* duk__get_min_grow_a() is always >= 1 */
48320
48321 duk__realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0);
48322}
48323
48324/* Abandon array part, moving array entries into entries part.
48325 * This requires a props resize, which is a heavy operation.
48326 * We also compact the entries part while we're at it, although
48327 * this is not strictly required.
48328 */
48329DUK_LOCAL void duk__abandon_array_checked(duk_hthread *thr, duk_hobject *obj) {
48330 duk_uint32_t new_e_size;
48331 duk_uint32_t new_a_size;
48332 duk_uint32_t new_h_size;
48333 duk_uint32_t e_used; /* actually used, non-NULL keys */
48334 duk_uint32_t a_used;
48335 duk_uint32_t a_size;
48336
48337 DUK_ASSERT(thr != NULL);
48338 DUK_ASSERT(obj != NULL);
48339
48340 e_used = duk__count_used_e_keys(thr, obj);
48341 duk__compute_a_stats(thr, obj, &a_used, &a_size);
48342
48343 /*
48344 * Must guarantee all actually used array entries will fit into
48345 * new entry part. Add one growth step to ensure we don't run out
48346 * of space right away.
48347 */
48348
48349 new_e_size = e_used + a_used;
48350 new_e_size = new_e_size + duk__get_min_grow_e(new_e_size);
48351 new_a_size = 0;
48352#if defined(DUK_USE_HOBJECT_HASH_PART)
48353 new_h_size = duk__get_default_h_size(new_e_size);
48354#else
48355 new_h_size = 0;
48356#endif
48357
48358 DUK_DD(DUK_DDPRINT("abandon array part for hobject %p, "
48359 "array stats before: e_used=%ld, a_used=%ld, a_size=%ld; "
48360 "resize to e_size=%ld, a_size=%ld, h_size=%ld",
48361 (void *) obj, (long) e_used, (long) a_used, (long) a_size,
48362 (long) new_e_size, (long) new_a_size, (long) new_h_size));
48363
48364 duk__realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 1);
48365}
48366
48367/*
48368 * Compact an object. Minimizes allocation size for objects which are
48369 * not likely to be extended. This is useful for internal and non-
48370 * extensible objects, but can also be called for non-extensible objects.
48371 * May abandon the array part if it is computed to be too sparse.
48372 *
48373 * This call is relatively expensive, as it needs to scan both the
48374 * entries and the array part.
48375 *
48376 * The call may fail due to allocation error.
48377 */
48378
48379DUK_INTERNAL void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj) {
48380 duk_uint32_t e_size; /* currently used -> new size */
48381 duk_uint32_t a_size; /* currently required */
48382 duk_uint32_t a_used; /* actually used */
48383 duk_uint32_t h_size;
48384 duk_bool_t abandon_array;
48385
48386 DUK_ASSERT(thr != NULL);
48387 DUK_ASSERT(obj != NULL);
48388
11fdf7f2
TL
48389#if defined(DUK_USE_ROM_OBJECTS)
48390 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
48391 DUK_DD(DUK_DDPRINT("ignore attempt to compact a rom object"));
48392 return;
48393 }
48394#endif
48395
7c673cae
FG
48396 e_size = duk__count_used_e_keys(thr, obj);
48397 duk__compute_a_stats(thr, obj, &a_used, &a_size);
48398
48399 DUK_DD(DUK_DDPRINT("compacting hobject, used e keys %ld, used a keys %ld, min a size %ld, "
48400 "resized array density would be: %ld/%ld = %lf",
48401 (long) e_size, (long) a_used, (long) a_size,
48402 (long) a_used, (long) a_size,
48403 (double) a_used / (double) a_size));
48404
48405 if (duk__abandon_array_density_check(a_used, a_size)) {
48406 DUK_DD(DUK_DDPRINT("decided to abandon array during compaction, a_used=%ld, a_size=%ld",
48407 (long) a_used, (long) a_size));
48408 abandon_array = 1;
48409 e_size += a_used;
48410 a_size = 0;
48411 } else {
48412 DUK_DD(DUK_DDPRINT("decided to keep array during compaction"));
48413 abandon_array = 0;
48414 }
48415
48416#if defined(DUK_USE_HOBJECT_HASH_PART)
48417 if (e_size >= DUK_HOBJECT_E_USE_HASH_LIMIT) {
48418 h_size = duk__get_default_h_size(e_size);
48419 } else {
48420 h_size = 0;
48421 }
48422#else
48423 h_size = 0;
48424#endif
48425
48426 DUK_DD(DUK_DDPRINT("compacting hobject -> new e_size %ld, new a_size=%ld, new h_size=%ld, abandon_array=%ld",
48427 (long) e_size, (long) a_size, (long) h_size, (long) abandon_array));
48428
48429 duk__realloc_props(thr, obj, e_size, a_size, h_size, abandon_array);
48430}
48431
48432/*
48433 * Find an existing key from entry part either by linear scan or by
48434 * using the hash index (if it exists).
48435 *
48436 * Sets entry index (and possibly the hash index) to output variables,
48437 * which allows the caller to update the entry and hash entries in-place.
48438 * If entry is not found, both values are set to -1. If entry is found
48439 * but there is no hash part, h_idx is set to -1.
48440 */
48441
48442DUK_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) {
48443 DUK_ASSERT(obj != NULL);
48444 DUK_ASSERT(key != NULL);
48445 DUK_ASSERT(e_idx != NULL);
48446 DUK_ASSERT(h_idx != NULL);
48447 DUK_UNREF(heap);
48448
48449 if (DUK_LIKELY(DUK_HOBJECT_GET_HSIZE(obj) == 0))
48450 {
48451 /* Linear scan: more likely because most objects are small.
48452 * This is an important fast path.
48453 *
48454 * XXX: this might be worth inlining for property lookups.
48455 */
48456 duk_uint_fast32_t i;
48457 duk_uint_fast32_t n;
48458 duk_hstring **h_keys_base;
48459 DUK_DDD(DUK_DDDPRINT("duk_hobject_find_existing_entry() using linear scan for lookup"));
48460
48461 h_keys_base = DUK_HOBJECT_E_GET_KEY_BASE(heap, obj);
48462 n = DUK_HOBJECT_GET_ENEXT(obj);
48463 for (i = 0; i < n; i++) {
48464 if (h_keys_base[i] == key) {
48465 *e_idx = i;
48466 *h_idx = -1;
48467 return;
48468 }
48469 }
48470 }
48471#if defined(DUK_USE_HOBJECT_HASH_PART)
48472 else
48473 {
48474 /* hash lookup */
48475 duk_uint32_t n;
48476 duk_uint32_t i, step;
48477 duk_uint32_t *h_base;
48478
48479 DUK_DDD(DUK_DDDPRINT("duk_hobject_find_existing_entry() using hash part for lookup"));
48480
48481 h_base = DUK_HOBJECT_H_GET_BASE(heap, obj);
48482 n = DUK_HOBJECT_GET_HSIZE(obj);
48483 i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n);
48484 step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key));
48485
48486 for (;;) {
48487 duk_uint32_t t;
48488
48489 DUK_ASSERT_DISABLE(i >= 0); /* unsigned */
48490 DUK_ASSERT(i < DUK_HOBJECT_GET_HSIZE(obj));
48491 t = h_base[i];
48492 DUK_ASSERT(t == DUK__HASH_UNUSED || t == DUK__HASH_DELETED ||
48493 (t < DUK_HOBJECT_GET_ESIZE(obj))); /* t >= 0 always true, unsigned */
48494
48495 if (t == DUK__HASH_UNUSED) {
48496 break;
48497 } else if (t == DUK__HASH_DELETED) {
48498 DUK_DDD(DUK_DDDPRINT("lookup miss (deleted) i=%ld, t=%ld",
48499 (long) i, (long) t));
48500 } else {
48501 DUK_ASSERT(t < DUK_HOBJECT_GET_ESIZE(obj));
48502 if (DUK_HOBJECT_E_GET_KEY(heap, obj, t) == key) {
48503 DUK_DDD(DUK_DDDPRINT("lookup hit i=%ld, t=%ld -> key %p",
48504 (long) i, (long) t, (void *) key));
48505 *e_idx = t;
48506 *h_idx = i;
48507 return;
48508 }
48509 DUK_DDD(DUK_DDDPRINT("lookup miss i=%ld, t=%ld",
48510 (long) i, (long) t));
48511 }
48512 i = (i + step) % n;
48513
48514 /* guaranteed to finish, as hash is never full */
48515 DUK_ASSERT(i != (duk_uint32_t) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n));
48516 }
48517 }
48518#endif /* DUK_USE_HOBJECT_HASH_PART */
48519
48520 /* not found */
48521 *e_idx = -1;
48522 *h_idx = -1;
48523}
48524
48525/* For internal use: get non-accessor entry value */
48526DUK_INTERNAL duk_tval *duk_hobject_find_existing_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_hstring *key) {
48527 duk_int_t e_idx;
48528 duk_int_t h_idx;
48529
48530 DUK_ASSERT(obj != NULL);
48531 DUK_ASSERT(key != NULL);
48532 DUK_UNREF(heap);
48533
48534 duk_hobject_find_existing_entry(heap, obj, key, &e_idx, &h_idx);
48535 if (e_idx >= 0 && !DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx)) {
48536 return DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx);
48537 } else {
48538 return NULL;
48539 }
48540}
48541
48542/* For internal use: get non-accessor entry value and attributes */
48543DUK_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) {
48544 duk_int_t e_idx;
48545 duk_int_t h_idx;
48546
48547 DUK_ASSERT(obj != NULL);
48548 DUK_ASSERT(key != NULL);
48549 DUK_ASSERT(out_attrs != NULL);
48550 DUK_UNREF(heap);
48551
48552 duk_hobject_find_existing_entry(heap, obj, key, &e_idx, &h_idx);
48553 if (e_idx >= 0 && !DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx)) {
48554 *out_attrs = DUK_HOBJECT_E_GET_FLAGS(heap, obj, e_idx);
48555 return DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx);
48556 } else {
48557 *out_attrs = 0;
48558 return NULL;
48559 }
48560}
48561
48562/* For internal use: get array part value */
48563DUK_INTERNAL duk_tval *duk_hobject_find_existing_array_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_uarridx_t i) {
48564 duk_tval *tv;
48565
48566 DUK_ASSERT(obj != NULL);
48567 DUK_UNREF(heap);
48568
48569 if (!DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
48570 return NULL;
48571 }
48572 if (i >= DUK_HOBJECT_GET_ASIZE(obj)) {
48573 return NULL;
48574 }
48575 tv = DUK_HOBJECT_A_GET_VALUE_PTR(heap, obj, i);
48576 return tv;
48577}
48578
48579/*
48580 * Allocate and initialize a new entry, resizing the properties allocation
48581 * if necessary. Returns entry index (e_idx) or throws an error if alloc fails.
48582 *
48583 * Sets the key of the entry (increasing the key's refcount), and updates
48584 * the hash part if it exists. Caller must set value and flags, and update
48585 * the entry value refcount. A decref for the previous value is not necessary.
48586 */
48587
48588DUK_LOCAL duk_bool_t duk__alloc_entry_checked(duk_hthread *thr, duk_hobject *obj, duk_hstring *key) {
48589 duk_uint32_t idx;
48590
48591 DUK_ASSERT(thr != NULL);
48592 DUK_ASSERT(obj != NULL);
48593 DUK_ASSERT(key != NULL);
48594 DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(obj) <= DUK_HOBJECT_GET_ESIZE(obj));
48595
48596#ifdef DUK_USE_ASSERTIONS
48597 /* key must not already exist in entry part */
48598 {
48599 duk_uint_fast32_t i;
48600 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
48601 DUK_ASSERT(DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i) != key);
48602 }
48603 }
48604#endif
48605
48606 if (DUK_HOBJECT_GET_ENEXT(obj) >= DUK_HOBJECT_GET_ESIZE(obj)) {
48607 /* only need to guarantee 1 more slot, but allocation growth is in chunks */
48608 DUK_DDD(DUK_DDDPRINT("entry part full, allocate space for one more entry"));
48609 duk__grow_props_for_new_entry_item(thr, obj);
48610 }
48611 DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(obj) < DUK_HOBJECT_GET_ESIZE(obj));
48612 idx = DUK_HOBJECT_POSTINC_ENEXT(obj);
48613
48614 /* previous value is assumed to be garbage, so don't touch it */
48615 DUK_HOBJECT_E_SET_KEY(thr->heap, obj, idx, key);
48616 DUK_HSTRING_INCREF(thr, key);
48617
48618#if defined(DUK_USE_HOBJECT_HASH_PART)
48619 if (DUK_UNLIKELY(DUK_HOBJECT_GET_HSIZE(obj) > 0)) {
48620 duk_uint32_t n;
48621 duk_uint32_t i, step;
48622 duk_uint32_t *h_base = DUK_HOBJECT_H_GET_BASE(thr->heap, obj);
48623
48624 n = DUK_HOBJECT_GET_HSIZE(obj);
48625 i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n);
48626 step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key));
48627
48628 for (;;) {
48629 duk_uint32_t t = h_base[i];
48630 if (t == DUK__HASH_UNUSED || t == DUK__HASH_DELETED) {
48631 DUK_DDD(DUK_DDDPRINT("duk__alloc_entry_checked() inserted key into hash part, %ld -> %ld",
48632 (long) i, (long) idx));
48633 DUK_ASSERT_DISABLE(i >= 0); /* unsigned */
48634 DUK_ASSERT(i < DUK_HOBJECT_GET_HSIZE(obj));
48635 DUK_ASSERT_DISABLE(idx >= 0);
48636 DUK_ASSERT(idx < DUK_HOBJECT_GET_ESIZE(obj));
48637 h_base[i] = idx;
48638 break;
48639 }
48640 DUK_DDD(DUK_DDDPRINT("duk__alloc_entry_checked() miss %ld", (long) i));
48641 i = (i + step) % n;
48642
48643 /* guaranteed to find an empty slot */
48644 DUK_ASSERT(i != (duk_uint32_t) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), DUK_HOBJECT_GET_HSIZE(obj)));
48645 }
48646 }
48647#endif /* DUK_USE_HOBJECT_HASH_PART */
48648
48649 /* Note: we could return the hash index here too, but it's not
48650 * needed right now.
48651 */
48652
48653 DUK_ASSERT_DISABLE(idx >= 0);
48654 DUK_ASSERT(idx < DUK_HOBJECT_GET_ESIZE(obj));
48655 DUK_ASSERT(idx < DUK_HOBJECT_GET_ENEXT(obj));
48656 return idx;
48657}
48658
48659/*
48660 * Object internal value
48661 *
48662 * Returned value is guaranteed to be reachable / incref'd, caller does not need
48663 * to incref OR decref. No proxies or accessors are invoked, no prototype walk.
48664 */
48665
48666DUK_INTERNAL duk_bool_t duk_hobject_get_internal_value(duk_heap *heap, duk_hobject *obj, duk_tval *tv_out) {
48667 duk_int_t e_idx;
48668 duk_int_t h_idx;
48669
48670 DUK_ASSERT(heap != NULL);
48671 DUK_ASSERT(obj != NULL);
48672 DUK_ASSERT(tv_out != NULL);
48673
7c673cae
FG
48674 /* always in entry part, no need to look up parents etc */
48675 duk_hobject_find_existing_entry(heap, obj, DUK_HEAP_STRING_INT_VALUE(heap), &e_idx, &h_idx);
48676 if (e_idx >= 0) {
48677 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx));
48678 DUK_TVAL_SET_TVAL(tv_out, DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx));
48679 return 1;
48680 }
11fdf7f2 48681 DUK_TVAL_SET_UNDEFINED(tv_out);
7c673cae
FG
48682 return 0;
48683}
48684
48685DUK_INTERNAL duk_hstring *duk_hobject_get_internal_value_string(duk_heap *heap, duk_hobject *obj) {
48686 duk_tval tv;
48687
48688 DUK_ASSERT(heap != NULL);
48689 DUK_ASSERT(obj != NULL);
48690
11fdf7f2
TL
48691 /* This is not strictly necessary, but avoids compiler warnings; e.g.
48692 * gcc won't reliably detect that no uninitialized data is read below.
48693 */
48694 DUK_MEMZERO((void *) &tv, sizeof(duk_tval));
48695
7c673cae
FG
48696 if (duk_hobject_get_internal_value(heap, obj, &tv)) {
48697 duk_hstring *h;
48698 DUK_ASSERT(DUK_TVAL_IS_STRING(&tv));
48699 h = DUK_TVAL_GET_STRING(&tv);
48700 return h;
48701 }
48702
48703 return NULL;
48704}
48705
48706/*
48707 * Arguments handling helpers (argument map mainly).
48708 *
48709 * An arguments object has exotic behavior for some numeric indices.
48710 * Accesses may translate to identifier operations which may have
48711 * arbitrary side effects (potentially invalidating any duk_tval
48712 * pointers).
48713 */
48714
48715/* Lookup 'key' from arguments internal 'map', perform a variable lookup
48716 * if mapped, and leave the result on top of stack (and return non-zero).
48717 * Used in E5 Section 10.6 algorithms [[Get]] and [[GetOwnProperty]].
48718 */
48719DUK_LOCAL
48720duk_bool_t duk__lookup_arguments_map(duk_hthread *thr,
48721 duk_hobject *obj,
48722 duk_hstring *key,
48723 duk_propdesc *temp_desc,
48724 duk_hobject **out_map,
48725 duk_hobject **out_varenv) {
48726 duk_context *ctx = (duk_context *) thr;
48727 duk_hobject *map;
48728 duk_hobject *varenv;
48729 duk_bool_t rc;
48730
48731 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
48732
48733 DUK_DDD(DUK_DDDPRINT("arguments map lookup: thr=%p, obj=%p, key=%p, temp_desc=%p "
48734 "(obj -> %!O, key -> %!O)",
48735 (void *) thr, (void *) obj, (void *) key, (void *) temp_desc,
48736 (duk_heaphdr *) obj, (duk_heaphdr *) key));
48737
11fdf7f2 48738 if (!duk_hobject_get_own_propdesc(thr, obj, DUK_HTHREAD_STRING_INT_MAP(thr), temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
7c673cae
FG
48739 DUK_DDD(DUK_DDDPRINT("-> no 'map'"));
48740 return 0;
48741 }
48742
48743 map = duk_require_hobject(ctx, -1);
48744 DUK_ASSERT(map != NULL);
48745 duk_pop(ctx); /* map is reachable through obj */
48746
11fdf7f2 48747 if (!duk_hobject_get_own_propdesc(thr, map, key, temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
7c673cae
FG
48748 DUK_DDD(DUK_DDDPRINT("-> 'map' exists, but key not in map"));
48749 return 0;
48750 }
48751
48752 /* [... varname] */
48753 DUK_DDD(DUK_DDDPRINT("-> 'map' exists, and contains key, key is mapped to argument/variable binding %!T",
48754 (duk_tval *) duk_get_tval(ctx, -1)));
48755 DUK_ASSERT(duk_is_string(ctx, -1)); /* guaranteed when building arguments */
48756
48757 /* get varenv for varname (callee's declarative lexical environment) */
11fdf7f2 48758 rc = duk_hobject_get_own_propdesc(thr, obj, DUK_HTHREAD_STRING_INT_VARENV(thr), temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE);
7c673cae
FG
48759 DUK_UNREF(rc);
48760 DUK_ASSERT(rc != 0); /* arguments MUST have an initialized lexical environment reference */
48761 varenv = duk_require_hobject(ctx, -1);
48762 DUK_ASSERT(varenv != NULL);
48763 duk_pop(ctx); /* varenv remains reachable through 'obj' */
48764
48765 DUK_DDD(DUK_DDDPRINT("arguments varenv is: %!dO", (duk_heaphdr *) varenv));
48766
48767 /* success: leave varname in stack */
48768 *out_map = map;
48769 *out_varenv = varenv;
48770 return 1; /* [... varname] */
48771}
48772
48773/* Lookup 'key' from arguments internal 'map', and leave replacement value
48774 * on stack top if mapped (and return non-zero).
48775 * Used in E5 Section 10.6 algorithm for [[GetOwnProperty]] (used by [[Get]]).
48776 */
48777DUK_LOCAL duk_bool_t duk__check_arguments_map_for_get(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc) {
48778 duk_context *ctx = (duk_context *) thr;
48779 duk_hobject *map;
48780 duk_hobject *varenv;
48781 duk_hstring *varname;
48782
48783 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
48784
48785 if (!duk__lookup_arguments_map(thr, obj, key, temp_desc, &map, &varenv)) {
48786 DUK_DDD(DUK_DDDPRINT("arguments: key not mapped, no exotic get behavior"));
48787 return 0;
48788 }
48789
48790 /* [... varname] */
48791
48792 varname = duk_require_hstring(ctx, -1);
48793 DUK_ASSERT(varname != NULL);
48794 duk_pop(ctx); /* varname is still reachable */
48795
48796 DUK_DDD(DUK_DDDPRINT("arguments object automatic getvar for a bound variable; "
48797 "key=%!O, varname=%!O",
48798 (duk_heaphdr *) key,
48799 (duk_heaphdr *) varname));
48800
48801 (void) duk_js_getvar_envrec(thr, varenv, varname, 1 /*throw*/);
48802
48803 /* [... value this_binding] */
48804
48805 duk_pop(ctx);
48806
48807 /* leave result on stack top */
48808 return 1;
48809}
48810
48811/* Lookup 'key' from arguments internal 'map', perform a variable write if mapped.
48812 * Used in E5 Section 10.6 algorithm for [[DefineOwnProperty]] (used by [[Put]]).
48813 * Assumes stack top contains 'put' value (which is NOT popped).
48814 */
48815DUK_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) {
48816 duk_context *ctx = (duk_context *) thr;
48817 duk_hobject *map;
48818 duk_hobject *varenv;
48819 duk_hstring *varname;
48820
48821 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
48822
48823 if (!duk__lookup_arguments_map(thr, obj, key, temp_desc, &map, &varenv)) {
48824 DUK_DDD(DUK_DDDPRINT("arguments: key not mapped, no exotic put behavior"));
48825 return;
48826 }
48827
48828 /* [... put_value varname] */
48829
48830 varname = duk_require_hstring(ctx, -1);
48831 DUK_ASSERT(varname != NULL);
48832 duk_pop(ctx); /* varname is still reachable */
48833
48834 DUK_DDD(DUK_DDDPRINT("arguments object automatic putvar for a bound variable; "
48835 "key=%!O, varname=%!O, value=%!T",
48836 (duk_heaphdr *) key,
48837 (duk_heaphdr *) varname,
48838 (duk_tval *) duk_require_tval(ctx, -1)));
48839
48840 /* [... put_value] */
48841
48842 /*
48843 * Note: although arguments object variable mappings are only established
48844 * for non-strict functions (and a call to a non-strict function created
48845 * the arguments object in question), an inner strict function may be doing
48846 * the actual property write. Hence the throw_flag applied here comes from
48847 * the property write call.
48848 */
48849
48850 duk_js_putvar_envrec(thr, varenv, varname, duk_require_tval(ctx, -1), throw_flag);
48851
48852 /* [... put_value] */
48853}
48854
48855/* Lookup 'key' from arguments internal 'map', delete mapping if found.
48856 * Used in E5 Section 10.6 algorithm for [[Delete]]. Note that the
48857 * variable/argument itself (where the map points) is not deleted.
48858 */
48859DUK_LOCAL void duk__check_arguments_map_for_delete(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc) {
48860 duk_context *ctx = (duk_context *) thr;
48861 duk_hobject *map;
48862
48863 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
48864
11fdf7f2 48865 if (!duk_hobject_get_own_propdesc(thr, obj, DUK_HTHREAD_STRING_INT_MAP(thr), temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
7c673cae
FG
48866 DUK_DDD(DUK_DDDPRINT("arguments: key not mapped, no exotic delete behavior"));
48867 return;
48868 }
48869
48870 map = duk_require_hobject(ctx, -1);
48871 DUK_ASSERT(map != NULL);
48872 duk_pop(ctx); /* map is reachable through obj */
48873
48874 DUK_DDD(DUK_DDDPRINT("-> have 'map', delete key %!O from map (if exists)); ignore result",
48875 (duk_heaphdr *) key));
48876
48877 /* Note: no recursion issue, we can trust 'map' to behave */
48878 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_BEHAVIOR(map));
48879 DUK_DDD(DUK_DDDPRINT("map before deletion: %!O", (duk_heaphdr *) map));
48880 (void) duk_hobject_delprop_raw(thr, map, key, 0); /* ignore result */
48881 DUK_DDD(DUK_DDDPRINT("map after deletion: %!O", (duk_heaphdr *) map));
48882}
48883
48884/*
48885 * Ecmascript compliant [[GetOwnProperty]](P), for internal use only.
48886 *
48887 * If property is found:
48888 * - Fills descriptor fields to 'out_desc'
11fdf7f2 48889 * - If DUK_GETDESC_FLAG_PUSH_VALUE is set, pushes a value related to the
7c673cae
FG
48890 * property onto the stack ('undefined' for accessor properties).
48891 * - Returns non-zero
48892 *
48893 * If property is not found:
48894 * - 'out_desc' is left in untouched state (possibly garbage)
11fdf7f2 48895 * - Nothing is pushed onto the stack (not even with DUK_GETDESC_FLAG_PUSH_VALUE
7c673cae
FG
48896 * set)
48897 * - Returns zero
48898 *
48899 * Notes:
48900 *
48901 * - Getting a property descriptor may cause an allocation (and hence
48902 * GC) to take place, hence reachability and refcount of all related
48903 * values matter. Reallocation of value stack, properties, etc may
48904 * invalidate many duk_tval pointers (concretely, those which reside
48905 * in memory areas subject to reallocation). However, heap object
48906 * pointers are never affected (heap objects have stable pointers).
48907 *
48908 * - The value of a plain property is always reachable and has a non-zero
48909 * reference count.
48910 *
48911 * - The value of a virtual property is not necessarily reachable from
48912 * elsewhere and may have a refcount of zero. Hence we push it onto
48913 * the valstack for the caller, which ensures it remains reachable
48914 * while it is needed.
48915 *
48916 * - There are no virtual accessor properties. Hence, all getters and
48917 * setters are always related to concretely stored properties, which
48918 * ensures that the get/set functions in the resulting descriptor are
48919 * reachable and have non-zero refcounts. Should there be virtual
48920 * accessor properties later, this would need to change.
48921 */
48922
11fdf7f2 48923DUK_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) {
7c673cae
FG
48924 duk_context *ctx = (duk_context *) thr;
48925 duk_tval *tv;
48926
11fdf7f2 48927 DUK_DDD(DUK_DDDPRINT("duk_hobject_get_own_propdesc: thr=%p, obj=%p, key=%p, out_desc=%p, flags=%lx, "
7c673cae
FG
48928 "arr_idx=%ld (obj -> %!O, key -> %!O)",
48929 (void *) thr, (void *) obj, (void *) key, (void *) out_desc,
48930 (long) flags, (long) arr_idx,
48931 (duk_heaphdr *) obj, (duk_heaphdr *) key));
48932
48933 DUK_ASSERT(ctx != NULL);
48934 DUK_ASSERT(thr != NULL);
48935 DUK_ASSERT(thr->heap != NULL);
48936 DUK_ASSERT(obj != NULL);
48937 DUK_ASSERT(key != NULL);
48938 DUK_ASSERT(out_desc != NULL);
48939 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
48940
48941 /* XXX: optimize this filling behavior later */
48942 out_desc->flags = 0;
48943 out_desc->get = NULL;
48944 out_desc->set = NULL;
48945 out_desc->e_idx = -1;
48946 out_desc->h_idx = -1;
48947 out_desc->a_idx = -1;
48948
48949 /*
48950 * Array part
48951 */
48952
48953 if (DUK_HOBJECT_HAS_ARRAY_PART(obj) && arr_idx != DUK__NO_ARRAY_INDEX) {
48954 if (arr_idx < DUK_HOBJECT_GET_ASIZE(obj)) {
48955 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx);
11fdf7f2 48956 if (!DUK_TVAL_IS_UNUSED(tv)) {
7c673cae 48957 DUK_DDD(DUK_DDDPRINT("-> found in array part"));
11fdf7f2 48958 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
7c673cae
FG
48959 duk_push_tval(ctx, tv);
48960 }
48961 /* implicit attributes */
48962 out_desc->flags = DUK_PROPDESC_FLAG_WRITABLE |
48963 DUK_PROPDESC_FLAG_CONFIGURABLE |
48964 DUK_PROPDESC_FLAG_ENUMERABLE;
48965 out_desc->a_idx = arr_idx;
48966 goto prop_found;
48967 }
48968 }
48969 /* assume array part is comprehensive (contains all array indexed elements
48970 * or none of them); hence no need to check the entries part here.
48971 */
48972 DUK_DDD(DUK_DDDPRINT("-> not found as a concrete property (has array part, "
48973 "should be there if present)"));
48974 goto prop_not_found_concrete;
48975 }
48976
48977 /*
48978 * Entries part
48979 */
48980
48981 duk_hobject_find_existing_entry(thr->heap, obj, key, &out_desc->e_idx, &out_desc->h_idx);
48982 if (out_desc->e_idx >= 0) {
48983 duk_int_t e_idx = out_desc->e_idx;
48984 out_desc->flags = DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, e_idx);
48985 if (out_desc->flags & DUK_PROPDESC_FLAG_ACCESSOR) {
48986 DUK_DDD(DUK_DDDPRINT("-> found accessor property in entry part"));
48987 out_desc->get = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, e_idx);
48988 out_desc->set = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, e_idx);
11fdf7f2 48989 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
7c673cae
FG
48990 /* a dummy undefined value is pushed to make valstack
48991 * behavior uniform for caller
48992 */
48993 duk_push_undefined(ctx);
48994 }
48995 } else {
48996 DUK_DDD(DUK_DDDPRINT("-> found plain property in entry part"));
48997 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx);
11fdf7f2 48998 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
7c673cae
FG
48999 duk_push_tval(ctx, tv);
49000 }
49001 }
49002 goto prop_found;
49003 }
49004
49005 /*
49006 * Not found as a concrete property, check whether a String object
49007 * virtual property matches.
49008 */
49009
49010 prop_not_found_concrete:
49011
49012 if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(obj)) {
49013 DUK_DDD(DUK_DDDPRINT("string object exotic property get for key: %!O, arr_idx: %ld",
49014 (duk_heaphdr *) key, (long) arr_idx));
49015
49016 if (arr_idx != DUK__NO_ARRAY_INDEX) {
49017 duk_hstring *h_val;
49018
49019 DUK_DDD(DUK_DDDPRINT("array index exists"));
49020
49021 h_val = duk_hobject_get_internal_value_string(thr->heap, obj);
49022 DUK_ASSERT(h_val);
49023 if (arr_idx < DUK_HSTRING_GET_CHARLEN(h_val)) {
49024 DUK_DDD(DUK_DDDPRINT("-> found, array index inside string"));
11fdf7f2 49025 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
7c673cae
FG
49026 duk_push_hstring(ctx, h_val);
49027 duk_substring(ctx, -1, arr_idx, arr_idx + 1); /* [str] -> [substr] */
49028 }
49029 out_desc->flags = DUK_PROPDESC_FLAG_ENUMERABLE | /* E5 Section 15.5.5.2 */
49030 DUK_PROPDESC_FLAG_VIRTUAL;
49031
49032 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
49033 return 1; /* cannot be e.g. arguments exotic, since exotic 'traits' are mutually exclusive */
49034 } else {
49035 /* index is above internal string length -> property is fully normal */
49036 DUK_DDD(DUK_DDDPRINT("array index outside string -> normal property"));
49037 }
49038 } else if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
49039 duk_hstring *h_val;
49040
49041 DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior"));
49042
49043 h_val = duk_hobject_get_internal_value_string(thr->heap, obj);
49044 DUK_ASSERT(h_val != NULL);
11fdf7f2 49045 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
7c673cae
FG
49046 duk_push_uint(ctx, (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h_val));
49047 }
49048 out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL; /* E5 Section 15.5.5.1 */
49049
49050 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
49051 return 1; /* cannot be arguments exotic */
49052 }
49053 } else if (DUK_HOBJECT_IS_BUFFEROBJECT(obj)) {
49054 duk_hbufferobject *h_bufobj;
49055 duk_uint_t byte_off;
49056 duk_small_uint_t elem_size;
49057
49058 h_bufobj = (duk_hbufferobject *) obj;
49059 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
49060 DUK_DDD(DUK_DDDPRINT("bufferobject property get for key: %!O, arr_idx: %ld",
49061 (duk_heaphdr *) key, (long) arr_idx));
49062
49063 if (arr_idx != DUK__NO_ARRAY_INDEX) {
49064 DUK_DDD(DUK_DDDPRINT("array index exists"));
49065
49066 /* Careful with wrapping: arr_idx upshift may easily wrap, whereas
49067 * length downshift won't.
49068 */
49069 if (arr_idx < (h_bufobj->length >> h_bufobj->shift)) {
49070 byte_off = arr_idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */
49071 elem_size = 1 << h_bufobj->shift;
11fdf7f2 49072 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
7c673cae
FG
49073 duk_uint8_t *data;
49074
49075 if (h_bufobj->buf != NULL && DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
49076 data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
49077 duk_hbufferobject_push_validated_read(ctx, h_bufobj, data, elem_size);
49078 } else {
49079 DUK_D(DUK_DPRINT("bufferobject access out of underlying buffer, ignoring (read zero)"));
49080 duk_push_uint(ctx, 0);
49081 }
49082 }
49083 out_desc->flags = DUK_PROPDESC_FLAG_WRITABLE |
49084 DUK_PROPDESC_FLAG_ENUMERABLE |
49085 DUK_PROPDESC_FLAG_VIRTUAL;
49086
49087 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
49088 return 1; /* cannot be e.g. arguments exotic, since exotic 'traits' are mutually exclusive */
49089 } else {
49090 /* index is above internal buffer length -> property is fully normal */
49091 DUK_DDD(DUK_DDDPRINT("array index outside buffer -> normal property"));
49092 }
49093 } else if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
49094 DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior"));
49095
11fdf7f2 49096 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
7c673cae
FG
49097 /* Length in elements: take into account shift, but
49098 * intentionally don't check the underlying buffer here.
49099 */
49100 duk_push_uint(ctx, h_bufobj->length >> h_bufobj->shift);
49101 }
49102 out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;
49103
49104 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
49105 return 1; /* cannot be arguments exotic */
49106 } else if (key == DUK_HTHREAD_STRING_BYTE_LENGTH(thr)) {
49107 /* If neutered must return 0; length is zeroed during
49108 * neutering.
49109 */
11fdf7f2 49110 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
7c673cae
FG
49111 duk_push_uint(ctx, h_bufobj->length);
49112 }
49113 out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;
49114 return 1; /* cannot be arguments exotic */
49115 } else if (key == DUK_HTHREAD_STRING_BYTE_OFFSET(thr)) {
49116 /* If neutered must return 0; offset is zeroed during
49117 * neutering.
49118 */
11fdf7f2 49119 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
7c673cae
FG
49120 duk_push_uint(ctx, h_bufobj->offset);
49121 }
49122 out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;
49123 return 1; /* cannot be arguments exotic */
49124 } else if (key == DUK_HTHREAD_STRING_BYTES_PER_ELEMENT(thr)) {
11fdf7f2 49125 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
7c673cae
FG
49126 duk_push_uint(ctx, 1 << h_bufobj->shift);
49127 }
49128 out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;
49129 return 1; /* cannot be arguments exotic */
49130 }
49131 } else if (DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(obj)) {
49132 DUK_DDD(DUK_DDDPRINT("duktape/c object exotic property get for key: %!O, arr_idx: %ld",
49133 (duk_heaphdr *) key, (long) arr_idx));
49134
49135 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
49136 DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior"));
49137
11fdf7f2 49138 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
7c673cae
FG
49139 duk_int16_t func_nargs = ((duk_hnativefunction *) obj)->nargs;
49140 duk_push_int(ctx, func_nargs == DUK_HNATIVEFUNCTION_NARGS_VARARGS ? 0 : func_nargs);
49141 }
49142 out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL; /* not enumerable */
49143
49144 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
49145 return 1; /* cannot be arguments exotic */
49146 }
49147 }
49148
49149 /* Array properties have exotic behavior but they are concrete,
49150 * so no special handling here.
49151 *
49152 * Arguments exotic behavior (E5 Section 10.6, [[GetOwnProperty]]
49153 * is only relevant as a post-check implemented below; hence no
49154 * check here.
49155 */
49156
49157 /*
49158 * Not found as concrete or virtual
49159 */
49160
49161 DUK_DDD(DUK_DDDPRINT("-> not found (virtual, entry part, or array part)"));
49162 return 0;
49163
49164 /*
49165 * Found
49166 *
49167 * Arguments object has exotic post-processing, see E5 Section 10.6,
49168 * description of [[GetOwnProperty]] variant for arguments.
49169 */
49170
49171 prop_found:
49172 DUK_DDD(DUK_DDDPRINT("-> property found, checking for arguments exotic post-behavior"));
49173
49174 /* Notes:
49175 * - only numbered indices are relevant, so arr_idx fast reject is good
49176 * (this is valid unless there are more than 4**32-1 arguments).
49177 * - since variable lookup has no side effects, this can be skipped if
11fdf7f2 49178 * DUK_GETDESC_FLAG_PUSH_VALUE is not set.
7c673cae
FG
49179 */
49180
49181 if (DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj) &&
49182 arr_idx != DUK__NO_ARRAY_INDEX &&
11fdf7f2 49183 (flags & DUK_GETDESC_FLAG_PUSH_VALUE)) {
7c673cae
FG
49184 duk_propdesc temp_desc;
49185
49186 /* Magically bound variable cannot be an accessor. However,
49187 * there may be an accessor property (or a plain property) in
49188 * place with magic behavior removed. This happens e.g. when
49189 * a magic property is redefined with defineProperty().
49190 * Cannot assert for "not accessor" here.
49191 */
49192
49193 /* replaces top of stack with new value if necessary */
11fdf7f2 49194 DUK_ASSERT((flags & DUK_GETDESC_FLAG_PUSH_VALUE) != 0);
7c673cae
FG
49195
49196 if (duk__check_arguments_map_for_get(thr, obj, key, &temp_desc)) {
49197 DUK_DDD(DUK_DDDPRINT("-> arguments exotic behavior overrides result: %!T -> %!T",
49198 (duk_tval *) duk_get_tval(ctx, -2),
49199 (duk_tval *) duk_get_tval(ctx, -1)));
49200 /* [... old_result result] -> [... result] */
49201 duk_remove(ctx, -2);
49202 }
49203 }
49204
49205 return 1;
49206}
49207
11fdf7f2 49208DUK_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) {
7c673cae
FG
49209 DUK_ASSERT(thr != NULL);
49210 DUK_ASSERT(obj != NULL);
49211 DUK_ASSERT(key != NULL);
49212 DUK_ASSERT(out_desc != NULL);
49213 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
49214
11fdf7f2 49215 return duk__get_own_propdesc_raw(thr, obj, key, DUK_HSTRING_GET_ARRIDX_SLOW(key), out_desc, flags);
7c673cae
FG
49216}
49217
49218/*
49219 * Ecmascript compliant [[GetProperty]](P), for internal use only.
49220 *
49221 * If property is found:
49222 * - Fills descriptor fields to 'out_desc'
11fdf7f2 49223 * - If DUK_GETDESC_FLAG_PUSH_VALUE is set, pushes a value related to the
7c673cae
FG
49224 * property onto the stack ('undefined' for accessor properties).
49225 * - Returns non-zero
49226 *
49227 * If property is not found:
49228 * - 'out_desc' is left in untouched state (possibly garbage)
11fdf7f2 49229 * - Nothing is pushed onto the stack (not even with DUK_GETDESC_FLAG_PUSH_VALUE
7c673cae
FG
49230 * set)
49231 * - Returns zero
49232 *
49233 * May cause arbitrary side effects and invalidate (most) duk_tval
49234 * pointers.
49235 */
49236
11fdf7f2 49237DUK_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) {
7c673cae
FG
49238 duk_hobject *curr;
49239 duk_uint32_t arr_idx;
49240 duk_uint_t sanity;
49241
49242 DUK_ASSERT(thr != NULL);
49243 DUK_ASSERT(thr->heap != NULL);
49244 DUK_ASSERT(obj != NULL);
49245 DUK_ASSERT(key != NULL);
49246 DUK_ASSERT(out_desc != NULL);
49247 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
49248
49249 arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key);
49250
11fdf7f2 49251 DUK_DDD(DUK_DDDPRINT("duk__get_propdesc: thr=%p, obj=%p, key=%p, out_desc=%p, flags=%lx, "
7c673cae
FG
49252 "arr_idx=%ld (obj -> %!O, key -> %!O)",
49253 (void *) thr, (void *) obj, (void *) key, (void *) out_desc,
49254 (long) flags, (long) arr_idx,
49255 (duk_heaphdr *) obj, (duk_heaphdr *) key));
49256
49257 curr = obj;
49258 DUK_ASSERT(curr != NULL);
49259 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
49260 do {
11fdf7f2 49261 if (duk__get_own_propdesc_raw(thr, curr, key, arr_idx, out_desc, flags)) {
7c673cae
FG
49262 /* stack contains value (if requested), 'out_desc' is set */
49263 return 1;
49264 }
49265
49266 /* not found in 'curr', next in prototype chain; impose max depth */
49267 if (sanity-- == 0) {
11fdf7f2 49268 if (flags & DUK_GETDESC_FLAG_IGNORE_PROTOLOOP) {
7c673cae
FG
49269 /* treat like property not found */
49270 break;
49271 } else {
11fdf7f2 49272 DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
7c673cae
FG
49273 }
49274 }
49275 curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
49276 } while (curr);
49277
49278 /* out_desc is left untouched (possibly garbage), caller must use return
49279 * value to determine whether out_desc can be looked up
49280 */
49281
49282 return 0;
49283}
49284
49285/*
49286 * Shallow fast path checks for accessing array elements with numeric
49287 * indices. The goal is to try to avoid coercing an array index to an
49288 * (interned) string for the most common lookups, in particular, for
49289 * standard Array objects.
49290 *
49291 * Interning is avoided but only for a very narrow set of cases:
49292 * - Object has array part, index is within array allocation, and
49293 * value is not unused (= key exists)
49294 * - Object has no interfering exotic behavior (e.g. arguments or
49295 * string object exotic behaviors interfere, array exotic
49296 * behavior does not).
49297 *
49298 * Current shortcoming: if key does not exist (even if it is within
49299 * the array allocation range) a slow path lookup with interning is
49300 * always required. This can probably be fixed so that there is a
49301 * quick fast path for non-existent elements as well, at least for
49302 * standard Array objects.
49303 */
49304
49305DUK_LOCAL duk_tval *duk__getprop_shallow_fastpath_array_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key) {
49306 duk_tval *tv;
49307 duk_uint32_t idx;
49308
49309 DUK_UNREF(thr);
49310
49311 if (!(DUK_HOBJECT_HAS_ARRAY_PART(obj) &&
49312 !DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj) &&
49313 !DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(obj) &&
49314 !DUK_HOBJECT_IS_BUFFEROBJECT(obj) &&
49315 !DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
49316 /* Must have array part and no conflicting exotic behaviors.
49317 * Doesn't need to have array special behavior, e.g. Arguments
49318 * object has array part.
49319 */
49320 return NULL;
49321 }
49322
49323 /* Arrays never have other exotic behaviors. */
49324
49325 DUK_DDD(DUK_DDDPRINT("fast path attempt (no exotic string/arguments/buffer "
49326 "behavior, object has array part)"));
49327
49328#if defined(DUK_USE_FASTINT)
49329 if (DUK_TVAL_IS_FASTINT(tv_key)) {
49330 idx = duk__tval_fastint_to_arr_idx(tv_key);
49331 } else
49332#endif
49333 if (DUK_TVAL_IS_DOUBLE(tv_key)) {
49334 idx = duk__tval_number_to_arr_idx(tv_key);
49335 } else {
49336 DUK_DDD(DUK_DDDPRINT("key is not a number"));
49337 return NULL;
49338 }
49339
49340 /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which
49341 * is 0xffffffffUL. We don't need to check for that explicitly
49342 * because 0xffffffffUL will never be inside object 'a_size'.
49343 */
49344
49345 if (idx >= DUK_HOBJECT_GET_ASIZE(obj)) {
49346 DUK_DDD(DUK_DDDPRINT("key is not an array index or outside array part"));
49347 return NULL;
49348 }
49349 DUK_ASSERT(idx != 0xffffffffUL);
49350 DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
49351
49352 /* XXX: for array instances we could take a shortcut here and assume
49353 * Array.prototype doesn't contain an array index property.
49354 */
49355
49356 DUK_DDD(DUK_DDDPRINT("key is a valid array index and inside array part"));
49357 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, idx);
11fdf7f2 49358 if (!DUK_TVAL_IS_UNUSED(tv)) {
7c673cae
FG
49359 DUK_DDD(DUK_DDDPRINT("-> fast path successful"));
49360 return tv;
49361 }
49362
49363 DUK_DDD(DUK_DDDPRINT("fast path attempt failed, fall back to slow path"));
49364 return NULL;
49365}
49366
49367DUK_LOCAL duk_bool_t duk__putprop_shallow_fastpath_array_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key, duk_tval *tv_val, duk_propdesc *temp_desc) {
49368 duk_tval *tv;
49369 duk_uint32_t idx;
7c673cae
FG
49370 duk_uint32_t old_len, new_len;
49371
49372 if (!(DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj) &&
49373 DUK_HOBJECT_HAS_ARRAY_PART(obj) &&
49374 DUK_HOBJECT_HAS_EXTENSIBLE(obj))) {
49375 return 0;
49376 }
11fdf7f2 49377 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); /* caller ensures */
7c673cae
FG
49378
49379#if defined(DUK_USE_FASTINT)
49380 if (DUK_TVAL_IS_FASTINT(tv_key)) {
49381 idx = duk__tval_fastint_to_arr_idx(tv_key);
49382 } else
49383#endif
49384 if (DUK_TVAL_IS_DOUBLE(tv_key)) {
49385 idx = duk__tval_number_to_arr_idx(tv_key);
49386 } else {
49387 DUK_DDD(DUK_DDDPRINT("key is not a number"));
49388 return 0;
49389 }
49390
49391 /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which
49392 * is 0xffffffffUL. We don't need to check for that explicitly
49393 * because 0xffffffffUL will never be inside object 'a_size'.
49394 */
49395
49396 if (idx >= DUK_HOBJECT_GET_ASIZE(obj)) { /* for resizing of array part, use slow path */
49397 return 0;
49398 }
49399 DUK_ASSERT(idx != 0xffffffffUL);
49400 DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
49401
49402 old_len = duk__get_old_array_length(thr, obj, temp_desc);
49403
49404 if (idx >= old_len) {
49405 DUK_DDD(DUK_DDDPRINT("write new array entry requires length update "
49406 "(arr_idx=%ld, old_len=%ld)",
49407 (long) idx, (long) old_len));
49408 if (!(temp_desc->flags & DUK_PROPDESC_FLAG_WRITABLE)) {
11fdf7f2 49409 DUK_ERROR_TYPE(thr, DUK_STR_NOT_WRITABLE);
7c673cae
FG
49410 return 0; /* not reachable */
49411 }
49412 new_len = idx + 1;
49413
49414 /* No resize has occurred so temp_desc->e_idx is still OK */
49415 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, temp_desc->e_idx);
49416 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
7c673cae 49417 DUK_TVAL_SET_FASTINT_U32(tv, new_len); /* no need for decref/incref because value is a number */
7c673cae
FG
49418 } else {
49419 ;
49420 }
49421
49422 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, idx);
11fdf7f2 49423 DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val); /* side effects */
7c673cae
FG
49424
49425 DUK_DDD(DUK_DDDPRINT("array fast path success for index %ld", (long) idx));
49426 return 1;
49427}
49428
49429/*
49430 * Fast path for bufferobject getprop/putprop
49431 */
49432
49433DUK_LOCAL duk_bool_t duk__getprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key) {
49434 duk_context *ctx;
49435 duk_uint32_t idx;
49436 duk_hbufferobject *h_bufobj;
49437 duk_uint_t byte_off;
49438 duk_small_uint_t elem_size;
49439 duk_uint8_t *data;
49440
49441 ctx = (duk_context *) thr;
49442
49443 if (!DUK_HOBJECT_IS_BUFFEROBJECT(obj)) {
49444 return 0;
49445 }
49446 h_bufobj = (duk_hbufferobject *) obj;
49447
49448#if defined(DUK_USE_FASTINT)
49449 if (DUK_TVAL_IS_FASTINT(tv_key)) {
49450 idx = duk__tval_fastint_to_arr_idx(tv_key);
49451 } else
49452#endif
49453 if (DUK_TVAL_IS_DOUBLE(tv_key)) {
49454 idx = duk__tval_number_to_arr_idx(tv_key);
49455 } else {
49456 return 0;
49457 }
49458
49459 /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which
49460 * is 0xffffffffUL. We don't need to check for that explicitly
49461 * because 0xffffffffUL will never be inside bufferobject length.
49462 */
49463
49464 /* Careful with wrapping (left shifting idx would be unsafe). */
49465 if (idx >= (h_bufobj->length >> h_bufobj->shift)) {
49466 return 0;
49467 }
49468 DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
49469
49470 byte_off = idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */
49471 elem_size = 1 << h_bufobj->shift;
49472
49473 if (h_bufobj->buf != NULL && DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
49474 data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
49475 duk_hbufferobject_push_validated_read(ctx, h_bufobj, data, elem_size);
49476 } else {
49477 DUK_D(DUK_DPRINT("bufferobject access out of underlying buffer, ignoring (read zero)"));
49478 duk_push_uint(ctx, 0);
49479 }
49480
49481 return 1;
49482}
49483
49484DUK_LOCAL duk_bool_t duk__putprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key, duk_tval *tv_val) {
49485 duk_context *ctx;
49486 duk_uint32_t idx;
49487 duk_hbufferobject *h_bufobj;
49488 duk_uint_t byte_off;
49489 duk_small_uint_t elem_size;
49490 duk_uint8_t *data;
49491
49492 ctx = (duk_context *) thr;
49493
49494 if (!(DUK_HOBJECT_IS_BUFFEROBJECT(obj) &&
49495 DUK_TVAL_IS_NUMBER(tv_val))) {
49496 return 0;
49497 }
11fdf7f2 49498 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); /* caller ensures; rom objects are never bufferobjects now */
7c673cae 49499
11fdf7f2 49500 h_bufobj = (duk_hbufferobject *) obj;
7c673cae
FG
49501#if defined(DUK_USE_FASTINT)
49502 if (DUK_TVAL_IS_FASTINT(tv_key)) {
49503 idx = duk__tval_fastint_to_arr_idx(tv_key);
49504 } else
49505#endif
49506 if (DUK_TVAL_IS_DOUBLE(tv_key)) {
49507 idx = duk__tval_number_to_arr_idx(tv_key);
49508 } else {
49509 return 0;
49510 }
49511
49512 /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which
49513 * is 0xffffffffUL. We don't need to check for that explicitly
49514 * because 0xffffffffUL will never be inside bufferobject length.
49515 */
49516
49517 /* Careful with wrapping (left shifting idx would be unsafe). */
49518 if (idx >= (h_bufobj->length >> h_bufobj->shift)) {
49519 return 0;
49520 }
49521 DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
49522
49523 byte_off = idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */
49524 elem_size = 1 << h_bufobj->shift;
49525
49526 /* Value is required to be a number in the fast path so there
49527 * are no side effects in write coercion.
49528 */
49529 duk_push_tval(ctx, tv_val);
49530 DUK_ASSERT(duk_is_number(ctx, -1));
49531
49532 if (h_bufobj->buf != NULL && DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
49533 data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
49534 duk_hbufferobject_validated_write(ctx, h_bufobj, data, elem_size);
49535 } else {
49536 DUK_D(DUK_DPRINT("bufferobject access out of underlying buffer, ignoring (write skipped)"));
49537 }
49538
49539 duk_pop(ctx);
49540 return 1;
49541}
49542
49543/*
49544 * GETPROP: Ecmascript property read.
49545 */
49546
49547DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key) {
49548 duk_context *ctx = (duk_context *) thr;
49549 duk_tval tv_obj_copy;
49550 duk_tval tv_key_copy;
49551 duk_hobject *curr = NULL;
49552 duk_hstring *key = NULL;
49553 duk_uint32_t arr_idx = DUK__NO_ARRAY_INDEX;
49554 duk_propdesc desc;
49555 duk_uint_t sanity;
49556
49557 DUK_DDD(DUK_DDDPRINT("getprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)",
49558 (void *) thr, (void *) tv_obj, (void *) tv_key,
49559 (duk_tval *) tv_obj, (duk_tval *) tv_key));
49560
49561 DUK_ASSERT(ctx != NULL);
49562 DUK_ASSERT(thr != NULL);
49563 DUK_ASSERT(thr->heap != NULL);
49564 DUK_ASSERT(tv_obj != NULL);
49565 DUK_ASSERT(tv_key != NULL);
49566
49567 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
49568
49569 /*
49570 * Make a copy of tv_obj, tv_key, and tv_val to avoid any issues of
49571 * them being invalidated by a valstack resize.
49572 *
49573 * XXX: this is now an overkill for many fast paths. Rework this
49574 * to be faster (although switching to a valstack discipline might
49575 * be a better solution overall).
49576 */
49577
49578 DUK_TVAL_SET_TVAL(&tv_obj_copy, tv_obj);
49579 DUK_TVAL_SET_TVAL(&tv_key_copy, tv_key);
49580 tv_obj = &tv_obj_copy;
49581 tv_key = &tv_key_copy;
49582
49583 /*
49584 * Coercion and fast path processing
49585 */
49586
49587 switch (DUK_TVAL_GET_TAG(tv_obj)) {
49588 case DUK_TAG_UNDEFINED:
49589 case DUK_TAG_NULL: {
49590 /* Note: unconditional throw */
49591 DUK_DDD(DUK_DDDPRINT("base object is undefined or null -> reject"));
11fdf7f2
TL
49592#if defined(DUK_USE_PARANOID_ERRORS)
49593 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
49594#else
49595 DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot read property %s of %s",
49596 duk_push_string_tval_readable(ctx, tv_key), duk_push_string_tval_readable(ctx, tv_obj));
49597#endif
7c673cae
FG
49598 return 0;
49599 }
49600
49601 case DUK_TAG_BOOLEAN: {
49602 DUK_DDD(DUK_DDDPRINT("base object is a boolean, start lookup from boolean prototype"));
49603 curr = thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE];
49604 break;
49605 }
49606
49607 case DUK_TAG_STRING: {
49608 duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj);
49609 duk_int_t pop_count;
49610
49611#if defined(DUK_USE_FASTINT)
49612 if (DUK_TVAL_IS_FASTINT(tv_key)) {
49613 arr_idx = duk__tval_fastint_to_arr_idx(tv_key);
49614 DUK_DDD(DUK_DDDPRINT("base object string, key is a fast-path fastint; arr_idx %ld", (long) arr_idx));
49615 pop_count = 0;
49616 } else
49617#endif
49618 if (DUK_TVAL_IS_NUMBER(tv_key)) {
49619 arr_idx = duk__tval_number_to_arr_idx(tv_key);
49620 DUK_DDD(DUK_DDDPRINT("base object string, key is a fast-path number; arr_idx %ld", (long) arr_idx));
49621 pop_count = 0;
49622 } else {
49623 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
49624 DUK_ASSERT(key != NULL);
49625 DUK_DDD(DUK_DDDPRINT("base object string, key is a non-fast-path number; after "
49626 "coercion key is %!T, arr_idx %ld",
49627 (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
49628 pop_count = 1;
49629 }
49630
49631 if (arr_idx != DUK__NO_ARRAY_INDEX &&
49632 arr_idx < DUK_HSTRING_GET_CHARLEN(h)) {
49633 duk_pop_n(ctx, pop_count);
49634 duk_push_hstring(ctx, h);
49635 duk_substring(ctx, -1, arr_idx, arr_idx + 1); /* [str] -> [substr] */
49636
49637 DUK_DDD(DUK_DDDPRINT("-> %!T (base is string, key is an index inside string length "
49638 "after coercion -> return char)",
49639 (duk_tval *) duk_get_tval(ctx, -1)));
49640 return 1;
49641 }
49642
49643 if (pop_count == 0) {
49644 /* This is a pretty awkward control flow, but we need to recheck the
49645 * key coercion here.
49646 */
49647 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
49648 DUK_ASSERT(key != NULL);
49649 DUK_DDD(DUK_DDDPRINT("base object string, key is a non-fast-path number; after "
49650 "coercion key is %!T, arr_idx %ld",
49651 (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
49652 }
49653
49654 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
49655 duk_pop(ctx); /* [key] -> [] */
49656 duk_push_uint(ctx, (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h)); /* [] -> [res] */
49657
49658 DUK_DDD(DUK_DDDPRINT("-> %!T (base is string, key is 'length' after coercion -> "
49659 "return string length)",
49660 (duk_tval *) duk_get_tval(ctx, -1)));
49661 return 1;
49662 }
49663 DUK_DDD(DUK_DDDPRINT("base object is a string, start lookup from string prototype"));
49664 curr = thr->builtins[DUK_BIDX_STRING_PROTOTYPE];
49665 goto lookup; /* avoid double coercion */
49666 }
49667
49668 case DUK_TAG_OBJECT: {
49669 duk_tval *tmp;
49670
49671 curr = DUK_TVAL_GET_OBJECT(tv_obj);
49672 DUK_ASSERT(curr != NULL);
49673
49674 tmp = duk__getprop_shallow_fastpath_array_tval(thr, curr, tv_key);
49675 if (tmp) {
49676 duk_push_tval(ctx, tmp);
49677
49678 DUK_DDD(DUK_DDDPRINT("-> %!T (base is object, key is a number, array part "
49679 "fast path)",
49680 (duk_tval *) duk_get_tval(ctx, -1)));
49681 return 1;
49682 }
49683
49684 if (duk__getprop_fastpath_bufobj_tval(thr, curr, tv_key) != 0) {
49685 /* Read value pushed on stack. */
49686 DUK_DDD(DUK_DDDPRINT("-> %!T (base is bufobj, key is a number, bufferobject "
49687 "fast path)",
49688 (duk_tval *) duk_get_tval(ctx, -1)));
49689 return 1;
49690 }
49691
49692#if defined(DUK_USE_ES6_PROXY)
49693 if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(curr))) {
49694 duk_hobject *h_target;
49695
49696 if (duk__proxy_check_prop(thr, curr, DUK_STRIDX_GET, tv_key, &h_target)) {
49697 /* -> [ ... trap handler ] */
49698 DUK_DDD(DUK_DDDPRINT("-> proxy object 'get' for key %!T", (duk_tval *) tv_key));
49699 duk_push_hobject(ctx, h_target); /* target */
49700 duk_push_tval(ctx, tv_key); /* P */
49701 duk_push_tval(ctx, tv_obj); /* Receiver: Proxy object */
49702 duk_call_method(ctx, 3 /*nargs*/);
49703
49704 /* Target object must be checked for a conflicting
49705 * non-configurable property.
49706 */
49707 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
49708 DUK_ASSERT(key != NULL);
49709
11fdf7f2 49710 if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
7c673cae
FG
49711 duk_tval *tv_hook = duk_require_tval(ctx, -3); /* value from hook */
49712 duk_tval *tv_targ = duk_require_tval(ctx, -1); /* value from target */
49713 duk_bool_t datadesc_reject;
49714 duk_bool_t accdesc_reject;
49715
49716 DUK_DDD(DUK_DDDPRINT("proxy 'get': target has matching property %!O, check for "
49717 "conflicting property; tv_hook=%!T, tv_targ=%!T, desc.flags=0x%08lx, "
49718 "desc.get=%p, desc.set=%p",
49719 (duk_heaphdr *) key, (duk_tval *) tv_hook, (duk_tval *) tv_targ,
49720 (unsigned long) desc.flags,
49721 (void *) desc.get, (void *) desc.set));
49722
49723 datadesc_reject = !(desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
49724 !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) &&
49725 !(desc.flags & DUK_PROPDESC_FLAG_WRITABLE) &&
49726 !duk_js_samevalue(tv_hook, tv_targ);
49727 accdesc_reject = (desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
49728 !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) &&
49729 (desc.get == NULL) &&
49730 !DUK_TVAL_IS_UNDEFINED(tv_hook);
49731 if (datadesc_reject || accdesc_reject) {
11fdf7f2 49732 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
7c673cae
FG
49733 }
49734
49735 duk_pop_2(ctx);
49736 } else {
49737 duk_pop(ctx);
49738 }
49739 return 1; /* return value */
49740 }
49741
49742 curr = h_target; /* resume lookup from target */
49743 DUK_TVAL_SET_OBJECT(tv_obj, curr);
49744 }
49745#endif /* DUK_USE_ES6_PROXY */
49746
49747 if (DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(curr)) {
49748 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
49749 DUK_ASSERT(key != NULL);
49750
49751 if (duk__check_arguments_map_for_get(thr, curr, key, &desc)) {
49752 DUK_DDD(DUK_DDDPRINT("-> %!T (base is object with arguments exotic behavior, "
49753 "key matches magically bound property -> skip standard "
49754 "Get with replacement value)",
49755 (duk_tval *) duk_get_tval(ctx, -1)));
49756
49757 /* no need for 'caller' post-check, because 'key' must be an array index */
49758
49759 duk_remove(ctx, -2); /* [key result] -> [result] */
49760 return 1;
49761 }
49762
49763 goto lookup; /* avoid double coercion */
49764 }
49765 break;
49766 }
49767
49768 /* Buffer has virtual properties similar to string, but indexed values
49769 * are numbers, not 1-byte buffers/strings which would perform badly.
49770 */
49771 case DUK_TAG_BUFFER: {
49772 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj);
49773 duk_int_t pop_count;
49774
49775 /*
49776 * Because buffer values are often looped over, a number fast path
49777 * is important.
49778 */
49779
49780#if defined(DUK_USE_FASTINT)
49781 if (DUK_TVAL_IS_FASTINT(tv_key)) {
49782 arr_idx = duk__tval_fastint_to_arr_idx(tv_key);
49783 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path fastint; arr_idx %ld", (long) arr_idx));
49784 pop_count = 0;
49785 }
49786 else
49787#endif
49788 if (DUK_TVAL_IS_NUMBER(tv_key)) {
49789 arr_idx = duk__tval_number_to_arr_idx(tv_key);
49790 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path number; arr_idx %ld", (long) arr_idx));
49791 pop_count = 0;
49792 } else {
49793 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
49794 DUK_ASSERT(key != NULL);
49795 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
49796 "coercion key is %!T, arr_idx %ld",
49797 (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
49798 pop_count = 1;
49799 }
49800
49801 if (arr_idx != DUK__NO_ARRAY_INDEX &&
49802 arr_idx < DUK_HBUFFER_GET_SIZE(h)) {
49803 duk_pop_n(ctx, pop_count);
49804 duk_push_uint(ctx, ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h))[arr_idx]);
49805
49806 DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is an index inside buffer length "
49807 "after coercion -> return byte as number)",
49808 (duk_tval *) duk_get_tval(ctx, -1)));
49809 return 1;
49810 }
49811
49812 if (pop_count == 0) {
49813 /* This is a pretty awkward control flow, but we need to recheck the
49814 * key coercion here.
49815 */
49816 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
49817 DUK_ASSERT(key != NULL);
49818 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
49819 "coercion key is %!T, arr_idx %ld",
49820 (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
49821 }
49822
49823 if (key == DUK_HTHREAD_STRING_LENGTH(thr) ||
49824 key == DUK_HTHREAD_STRING_BYTE_LENGTH(thr)) {
49825 duk_pop(ctx); /* [key] -> [] */
49826 duk_push_uint(ctx, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h)); /* [] -> [res] */
49827
49828 DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is 'length' or 'byteLength' "
49829 "after coercion -> return buffer length)",
49830 (duk_tval *) duk_get_tval(ctx, -1)));
49831 return 1;
49832 } else if (key == DUK_HTHREAD_STRING_BYTE_OFFSET(thr)) {
49833 duk_pop(ctx); /* [key] -> [] */
49834 duk_push_uint(ctx, 0); /* [] -> [res] */
49835
49836 DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is 'byteOffset' after coercion -> "
49837 "return 0 for consistency with Buffer objects)",
49838 (duk_tval *) duk_get_tval(ctx, -1)));
49839 return 1;
49840 } else if (key == DUK_HTHREAD_STRING_BYTES_PER_ELEMENT(thr)) {
49841 duk_pop(ctx); /* [key] -> [] */
49842 duk_push_uint(ctx, 1); /* [] -> [res] */
49843
49844 DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is 'BYTES_PER_ELEMENT' after coercion -> "
49845 "return 1 for consistency with Buffer objects)",
49846 (duk_tval *) duk_get_tval(ctx, -1)));
49847 return 1;
49848 }
49849
49850 DUK_DDD(DUK_DDDPRINT("base object is a buffer, start lookup from buffer prototype"));
49851 curr = thr->builtins[DUK_BIDX_BUFFER_PROTOTYPE];
49852 goto lookup; /* avoid double coercion */
49853 }
49854
49855 case DUK_TAG_POINTER: {
49856 DUK_DDD(DUK_DDDPRINT("base object is a pointer, start lookup from pointer prototype"));
49857 curr = thr->builtins[DUK_BIDX_POINTER_PROTOTYPE];
49858 break;
49859 }
49860
49861 case DUK_TAG_LIGHTFUNC: {
49862 duk_int_t lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv_obj);
49863
49864 /* Must coerce key: if key is an object, it may coerce to e.g. 'length'. */
49865 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
49866
49867 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
49868 duk_int_t lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
49869 duk_pop(ctx);
49870 duk_push_int(ctx, lf_len);
49871 return 1;
49872 } else if (key == DUK_HTHREAD_STRING_NAME(thr)) {
49873 duk_pop(ctx);
49874 duk_push_lightfunc_name(ctx, tv_obj);
49875 return 1;
49876 }
49877
49878 DUK_DDD(DUK_DDDPRINT("base object is a lightfunc, start lookup from function prototype"));
49879 curr = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
49880 goto lookup; /* avoid double coercion */
49881 }
49882
49883#if defined(DUK_USE_FASTINT)
49884 case DUK_TAG_FASTINT:
49885#endif
49886 default: {
49887 /* number */
49888 DUK_DDD(DUK_DDDPRINT("base object is a number, start lookup from number prototype"));
11fdf7f2 49889 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_obj));
7c673cae
FG
49890 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_obj));
49891 curr = thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE];
49892 break;
49893 }
49894 }
49895
49896 /* key coercion (unless already coerced above) */
49897 DUK_ASSERT(key == NULL);
49898 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
49899 DUK_ASSERT(key != NULL);
49900
49901 /*
49902 * Property lookup
49903 */
49904
49905 lookup:
49906 /* [key] (coerced) */
49907 DUK_ASSERT(curr != NULL);
49908 DUK_ASSERT(key != NULL);
49909
49910 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
49911 do {
11fdf7f2 49912 if (!duk__get_own_propdesc_raw(thr, curr, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
7c673cae
FG
49913 goto next_in_chain;
49914 }
49915
49916 if (desc.get != NULL) {
49917 /* accessor with defined getter */
49918 DUK_ASSERT((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) != 0);
49919
49920 duk_pop(ctx); /* [key undefined] -> [key] */
49921 duk_push_hobject(ctx, desc.get);
49922 duk_push_tval(ctx, tv_obj); /* note: original, uncoerced base */
49923#ifdef DUK_USE_NONSTD_GETTER_KEY_ARGUMENT
49924 duk_dup(ctx, -3);
49925 duk_call_method(ctx, 1); /* [key getter this key] -> [key retval] */
49926#else
49927 duk_call_method(ctx, 0); /* [key getter this] -> [key retval] */
49928#endif
49929 } else {
49930 /* [key value] or [key undefined] */
49931
49932 /* data property or accessor without getter */
49933 DUK_ASSERT(((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0) ||
49934 (desc.get == NULL));
49935
49936 /* if accessor without getter, return value is undefined */
49937 DUK_ASSERT(((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0) ||
49938 duk_is_undefined(ctx, -1));
49939
49940 /* Note: for an accessor without getter, falling through to
49941 * check for "caller" exotic behavior is unnecessary as
49942 * "undefined" will never activate the behavior. But it does
49943 * no harm, so we'll do it anyway.
49944 */
49945 }
49946
49947 goto found; /* [key result] */
49948
49949 next_in_chain:
49950 /* XXX: option to pretend property doesn't exist if sanity limit is
49951 * hit might be useful.
49952 */
49953 if (sanity-- == 0) {
11fdf7f2 49954 DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
7c673cae
FG
49955 }
49956 curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
49957 } while (curr);
49958
49959 /*
49960 * Not found
49961 */
49962
49963 duk_to_undefined(ctx, -1); /* [key] -> [undefined] (default value) */
49964
49965 DUK_DDD(DUK_DDDPRINT("-> %!T (not found)", (duk_tval *) duk_get_tval(ctx, -1)));
49966 return 0;
49967
49968 /*
49969 * Found; post-processing (Function and arguments objects)
49970 */
49971
49972 found:
49973 /* [key result] */
49974
49975#if !defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
49976 /* Special behavior for 'caller' property of (non-bound) function objects
49977 * and non-strict Arguments objects: if 'caller' -value- (!) is a strict
49978 * mode function, throw a TypeError (E5 Sections 15.3.5.4, 10.6).
49979 * Quite interestingly, a non-strict function with no formal arguments
49980 * will get an arguments object -without- special 'caller' behavior!
49981 *
49982 * The E5.1 spec is a bit ambiguous if this special behavior applies when
49983 * a bound function is the base value (not the 'caller' value): Section
49984 * 15.3.4.5 (describing bind()) states that [[Get]] for bound functions
49985 * matches that of Section 15.3.5.4 ([[Get]] for Function instances).
49986 * However, Section 13.3.5.4 has "NOTE: Function objects created using
49987 * Function.prototype.bind use the default [[Get]] internal method."
49988 * The current implementation assumes this means that bound functions
49989 * should not have the special [[Get]] behavior.
49990 *
49991 * The E5.1 spec is also a bit unclear if the TypeError throwing is
49992 * applied if the 'caller' value is a strict bound function. The
49993 * current implementation will throw even for both strict non-bound
49994 * and strict bound functions.
49995 *
49996 * See test-dev-strict-func-as-caller-prop-value.js for quite extensive
49997 * tests.
49998 *
49999 * This exotic behavior is disabled when the non-standard 'caller' property
50000 * is enabled, as it conflicts with the free use of 'caller'.
50001 */
50002 if (key == DUK_HTHREAD_STRING_CALLER(thr) &&
50003 DUK_TVAL_IS_OBJECT(tv_obj)) {
50004 duk_hobject *orig = DUK_TVAL_GET_OBJECT(tv_obj);
50005 DUK_ASSERT(orig != NULL);
50006
50007 if (DUK_HOBJECT_IS_NONBOUND_FUNCTION(orig) ||
50008 DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(orig)) {
50009 duk_hobject *h;
50010
50011 /* XXX: The TypeError is currently not applied to bound
50012 * functions because the 'strict' flag is not copied by
50013 * bind(). This may or may not be correct, the specification
50014 * only refers to the value being a "strict mode Function
50015 * object" which is ambiguous.
50016 */
50017 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(orig));
50018
50019 h = duk_get_hobject(ctx, -1); /* NULL if not an object */
50020 if (h &&
50021 DUK_HOBJECT_IS_FUNCTION(h) &&
50022 DUK_HOBJECT_HAS_STRICT(h)) {
50023 /* XXX: sufficient to check 'strict', assert for 'is function' */
11fdf7f2 50024 DUK_ERROR_TYPE(thr, DUK_STR_STRICT_CALLER_READ);
7c673cae
FG
50025 }
50026 }
50027 }
50028#endif /* !DUK_USE_NONSTD_FUNC_CALLER_PROPERTY */
50029
50030 duk_remove(ctx, -2); /* [key result] -> [result] */
50031
50032 DUK_DDD(DUK_DDDPRINT("-> %!T (found)", (duk_tval *) duk_get_tval(ctx, -1)));
50033 return 1;
50034}
50035
50036/*
50037 * HASPROP: Ecmascript property existence check ("in" operator).
50038 *
50039 * Interestingly, the 'in' operator does not do any coercion of
50040 * the target object.
50041 */
50042
50043DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key) {
50044 duk_context *ctx = (duk_context *) thr;
50045 duk_tval tv_key_copy;
50046 duk_hobject *obj;
50047 duk_hstring *key;
50048 duk_uint32_t arr_idx;
50049 duk_bool_t rc;
50050 duk_propdesc desc;
50051
50052 DUK_DDD(DUK_DDDPRINT("hasprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)",
50053 (void *) thr, (void *) tv_obj, (void *) tv_key,
50054 (duk_tval *) tv_obj, (duk_tval *) tv_key));
50055
50056 DUK_ASSERT(thr != NULL);
50057 DUK_ASSERT(thr->heap != NULL);
50058 DUK_ASSERT(tv_obj != NULL);
50059 DUK_ASSERT(tv_key != NULL);
50060 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
50061
50062 DUK_TVAL_SET_TVAL(&tv_key_copy, tv_key);
50063 tv_key = &tv_key_copy;
50064
50065 /*
50066 * The 'in' operator requires an object as its right hand side,
50067 * throwing a TypeError unconditionally if this is not the case.
50068 *
50069 * However, lightfuncs need to behave like fully fledged objects
50070 * here to be maximally transparent, so we need to handle them
50071 * here.
50072 */
50073
50074 /* XXX: Refactor key coercion so that it's only called once. It can't
50075 * be trivially lifted here because the object must be type checked
50076 * first.
50077 */
50078
50079 if (DUK_TVAL_IS_OBJECT(tv_obj)) {
50080 obj = DUK_TVAL_GET_OBJECT(tv_obj);
50081 DUK_ASSERT(obj != NULL);
50082
50083 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
50084 } else if (DUK_TVAL_IS_LIGHTFUNC(tv_obj)) {
50085 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
50086 if (duk__key_is_lightfunc_ownprop(thr, key)) {
50087 /* FOUND */
50088 rc = 1;
50089 goto pop_and_return;
50090 }
50091
50092 /* If not found, resume existence check from Function.prototype.
50093 * We can just substitute the value in this case; nothing will
50094 * need the original base value (as would be the case with e.g.
50095 * setters/getters.
50096 */
50097 obj = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
50098 } else {
50099 /* Note: unconditional throw */
50100 DUK_DDD(DUK_DDDPRINT("base object is not an object -> reject"));
11fdf7f2 50101 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
7c673cae
FG
50102 }
50103
50104 /* XXX: fast path for arrays? */
50105
50106 DUK_ASSERT(key != NULL);
50107 DUK_ASSERT(obj != NULL);
50108 DUK_UNREF(arr_idx);
50109
50110#if defined(DUK_USE_ES6_PROXY)
50111 if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
50112 duk_hobject *h_target;
50113 duk_bool_t tmp_bool;
50114
50115 /* XXX: the key in 'key in obj' is string coerced before we're called
50116 * (which is the required behavior in E5/E5.1/E6) so the key is a string
50117 * here already.
50118 */
50119
50120 if (duk__proxy_check_prop(thr, obj, DUK_STRIDX_HAS, tv_key, &h_target)) {
50121 /* [ ... key trap handler ] */
50122 DUK_DDD(DUK_DDDPRINT("-> proxy object 'has' for key %!T", (duk_tval *) tv_key));
50123 duk_push_hobject(ctx, h_target); /* target */
50124 duk_push_tval(ctx, tv_key); /* P */
50125 duk_call_method(ctx, 2 /*nargs*/);
50126 tmp_bool = duk_to_boolean(ctx, -1);
50127 if (!tmp_bool) {
50128 /* Target object must be checked for a conflicting
50129 * non-configurable property.
50130 */
50131
11fdf7f2 50132 if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */
7c673cae
FG
50133 DUK_DDD(DUK_DDDPRINT("proxy 'has': target has matching property %!O, check for "
50134 "conflicting property; desc.flags=0x%08lx, "
50135 "desc.get=%p, desc.set=%p",
50136 (duk_heaphdr *) key, (unsigned long) desc.flags,
50137 (void *) desc.get, (void *) desc.set));
50138 /* XXX: Extensibility check for target uses IsExtensible(). If we
50139 * implemented the isExtensible trap and didn't reject proxies as
50140 * proxy targets, it should be respected here.
50141 */
50142 if (!((desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && /* property is configurable and */
50143 DUK_HOBJECT_HAS_EXTENSIBLE(h_target))) { /* ... target is extensible */
11fdf7f2 50144 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
7c673cae
FG
50145 }
50146 }
50147 }
50148
50149 duk_pop_2(ctx); /* [ key trap_result ] -> [] */
50150 return tmp_bool;
50151 }
50152
50153 obj = h_target; /* resume check from proxy target */
50154 }
50155#endif /* DUK_USE_ES6_PROXY */
50156
50157 /* XXX: inline into a prototype walking loop? */
50158
11fdf7f2 50159 rc = duk__get_propdesc(thr, obj, key, &desc, 0 /*flags*/); /* don't push value */
7c673cae
FG
50160 /* fall through */
50161
50162 pop_and_return:
50163 duk_pop(ctx); /* [ key ] -> [] */
50164 return rc;
50165}
50166
50167/*
50168 * HASPROP variant used internally.
50169 *
50170 * This primitive must never throw an error, callers rely on this.
50171 * In particular, don't throw an error for prototype loops; instead,
50172 * pretend like the property doesn't exist if a prototype sanity limit
50173 * is reached.
50174 *
50175 * Does not implement proxy behavior: if applied to a proxy object,
50176 * returns key existence on the proxy object itself.
50177 */
50178
50179DUK_INTERNAL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key) {
50180 duk_propdesc dummy;
50181
50182 DUK_ASSERT(thr != NULL);
50183 DUK_ASSERT(thr->heap != NULL);
50184 DUK_ASSERT(obj != NULL);
50185 DUK_ASSERT(key != NULL);
50186
50187 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
50188
11fdf7f2 50189 return duk__get_propdesc(thr, obj, key, &dummy, DUK_GETDESC_FLAG_IGNORE_PROTOLOOP); /* don't push value */
7c673cae
FG
50190}
50191
50192/*
50193 * Helper: handle Array object 'length' write which automatically
50194 * deletes properties, see E5 Section 15.4.5.1, step 3. This is
50195 * quite tricky to get right.
50196 *
50197 * Used by duk_hobject_putprop().
50198 */
50199
50200DUK_LOCAL duk_uint32_t duk__get_old_array_length(duk_hthread *thr, duk_hobject *obj, duk_propdesc *temp_desc) {
50201 duk_bool_t rc;
50202 duk_tval *tv;
50203 duk_uint32_t res;
50204
50205 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
50206
50207 /* This function is only called for objects with array exotic behavior.
50208 * The [[DefineOwnProperty]] algorithm for arrays requires that
50209 * 'length' can never have a value outside the unsigned 32-bit range,
50210 * attempt to write such a value is a RangeError. Here we can thus
50211 * assert for this. When Duktape internals go around the official
50212 * property write interface (doesn't happen often) this assumption is
50213 * easy to accidentally break, so such code must be written carefully.
50214 * See test-bi-array-push-maxlen.js.
50215 */
50216
11fdf7f2 50217 rc = duk__get_own_propdesc_raw(thr, obj, DUK_HTHREAD_STRING_LENGTH(thr), DUK__NO_ARRAY_INDEX, temp_desc, 0 /*flags*/); /* don't push value */
7c673cae
FG
50218 DUK_UNREF(rc);
50219 DUK_ASSERT(rc != 0); /* arrays MUST have a 'length' property */
50220 DUK_ASSERT(temp_desc->e_idx >= 0);
50221
50222 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, temp_desc->e_idx);
50223 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); /* array 'length' is always a number, as we coerce it */
50224 DUK_ASSERT(DUK_TVAL_GET_NUMBER(tv) >= 0.0);
50225 DUK_ASSERT(DUK_TVAL_GET_NUMBER(tv) <= (double) 0xffffffffUL);
50226 DUK_ASSERT((duk_double_t) (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv) == DUK_TVAL_GET_NUMBER(tv));
50227#if defined(DUK_USE_FASTINT)
50228 /* Downgrade checks are not made everywhere, so 'length' is not always
50229 * a fastint (it is a number though). This can be removed once length
50230 * is always guaranteed to be a fastint.
50231 */
50232 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv) || DUK_TVAL_IS_DOUBLE(tv));
50233 if (DUK_TVAL_IS_FASTINT(tv)) {
50234 res = (duk_uint32_t) DUK_TVAL_GET_FASTINT_U32(tv);
50235 } else {
50236 res = (duk_uint32_t) DUK_TVAL_GET_DOUBLE(tv);
50237 }
50238#else
50239 res = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv);
50240#endif /* DUK_USE_FASTINT */
50241
50242 return res;
50243}
50244
50245DUK_LOCAL duk_uint32_t duk__to_new_array_length_checked(duk_hthread *thr) {
50246 duk_context *ctx = (duk_context *) thr;
50247 duk_uint32_t res;
50248 duk_double_t d;
50249
50250 /* Input value should be on stack top and will be coerced and
50251 * popped. Refuse to update an Array's 'length' to a value
50252 * outside the 32-bit range. Negative zero is accepted as zero.
50253 */
50254
50255 /* XXX: fastint */
50256
50257 d = duk_to_number(ctx, -1);
50258 res = (duk_uint32_t) d;
50259 if ((duk_double_t) res != d) {
11fdf7f2 50260 DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARRAY_LENGTH);
7c673cae
FG
50261 }
50262 duk_pop(ctx);
50263 return res;
50264}
50265
50266/* Delete elements required by a smaller length, taking into account
50267 * potentially non-configurable elements. Returns non-zero if all
50268 * elements could be deleted, and zero if all or some elements could
50269 * not be deleted. Also writes final "target length" to 'out_result_len'.
50270 * This is the length value that should go into the 'length' property
50271 * (must be set by the caller). Never throws an error.
50272 */
50273DUK_LOCAL
50274duk_bool_t duk__handle_put_array_length_smaller(duk_hthread *thr,
50275 duk_hobject *obj,
50276 duk_uint32_t old_len,
50277 duk_uint32_t new_len,
50278 duk_bool_t force_flag,
50279 duk_uint32_t *out_result_len) {
50280 duk_uint32_t target_len;
50281 duk_uint_fast32_t i;
50282 duk_uint32_t arr_idx;
50283 duk_hstring *key;
50284 duk_tval *tv;
7c673cae
FG
50285 duk_bool_t rc;
50286
50287 DUK_DDD(DUK_DDDPRINT("new array length smaller than old (%ld -> %ld), "
50288 "probably need to remove elements",
50289 (long) old_len, (long) new_len));
50290
50291 /*
50292 * New length is smaller than old length, need to delete properties above
50293 * the new length.
50294 *
50295 * If array part exists, this is straightforward: array entries cannot
50296 * be non-configurable so this is guaranteed to work.
50297 *
50298 * If array part does not exist, array-indexed values are scattered
50299 * in the entry part, and some may not be configurable (preventing length
50300 * from becoming lower than their index + 1). To handle the algorithm
50301 * in E5 Section 15.4.5.1, step l correctly, we scan the entire property
50302 * set twice.
50303 */
50304
50305 DUK_ASSERT(thr != NULL);
50306 DUK_ASSERT(obj != NULL);
50307 DUK_ASSERT(new_len < old_len);
50308 DUK_ASSERT(out_result_len != NULL);
50309 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
50310
50311 if (DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
50312 /*
50313 * All defined array-indexed properties are in the array part
50314 * (we assume the array part is comprehensive), and all array
50315 * entries are writable, configurable, and enumerable. Thus,
50316 * nothing can prevent array entries from being deleted.
50317 */
50318
50319 DUK_DDD(DUK_DDDPRINT("have array part, easy case"));
50320
50321 if (old_len < DUK_HOBJECT_GET_ASIZE(obj)) {
50322 /* XXX: assertion that entries >= old_len are already unused */
50323 i = old_len;
50324 } else {
50325 i = DUK_HOBJECT_GET_ASIZE(obj);
50326 }
50327 DUK_ASSERT(i <= DUK_HOBJECT_GET_ASIZE(obj));
50328
50329 while (i > new_len) {
50330 i--;
50331 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i);
11fdf7f2 50332 DUK_TVAL_SET_UNUSED_UPDREF(thr, tv); /* side effects */
7c673cae
FG
50333 }
50334
50335 *out_result_len = new_len;
50336 return 1;
50337 } else {
50338 /*
50339 * Entries part is a bit more complex
50340 */
50341
50342 /* Stage 1: find highest preventing non-configurable entry (if any).
50343 * When forcing, ignore non-configurability.
50344 */
50345
50346 DUK_DDD(DUK_DDDPRINT("no array part, slow case"));
50347
50348 DUK_DDD(DUK_DDDPRINT("array length write, no array part, stage 1: find target_len "
50349 "(highest preventing non-configurable entry (if any))"));
50350
50351 target_len = new_len;
50352 if (force_flag) {
50353 DUK_DDD(DUK_DDDPRINT("array length write, no array part; force flag -> skip stage 1"));
50354 goto skip_stage1;
50355 }
50356 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
50357 key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i);
50358 if (!key) {
50359 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: null key", (long) i));
50360 continue;
50361 }
50362 if (!DUK_HSTRING_HAS_ARRIDX(key)) {
50363 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key not an array index", (long) i));
50364 continue;
50365 }
50366
50367 DUK_ASSERT(DUK_HSTRING_HAS_ARRIDX(key)); /* XXX: macro checks for array index flag, which is unnecessary here */
50368 arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
50369 DUK_ASSERT(arr_idx != DUK__NO_ARRAY_INDEX);
50370 DUK_ASSERT(arr_idx < old_len); /* consistency requires this */
50371
50372 if (arr_idx < new_len) {
50373 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key is array index %ld, below new_len",
50374 (long) i, (long) arr_idx));
50375 continue;
50376 }
50377 if (DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(thr->heap, obj, i)) {
50378 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key is a relevant array index %ld, but configurable",
50379 (long) i, (long) arr_idx));
50380 continue;
50381 }
50382
50383 /* relevant array index is non-configurable, blocks write */
50384 if (arr_idx >= target_len) {
50385 DUK_DDD(DUK_DDDPRINT("entry at index %ld has arr_idx %ld, is not configurable, "
50386 "update target_len %ld -> %ld",
50387 (long) i, (long) arr_idx, (long) target_len,
50388 (long) (arr_idx + 1)));
50389 target_len = arr_idx + 1;
50390 }
50391 }
50392 skip_stage1:
50393
50394 /* stage 2: delete configurable entries above target length */
50395
50396 DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld, target_len=%ld",
50397 (long) old_len, (long) new_len, (long) target_len));
50398
50399 DUK_DDD(DUK_DDDPRINT("array length write, no array part, stage 2: remove "
50400 "entries >= target_len"));
50401
50402 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
50403 key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i);
50404 if (!key) {
50405 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: null key", (long) i));
50406 continue;
50407 }
50408 if (!DUK_HSTRING_HAS_ARRIDX(key)) {
50409 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key not an array index", (long) i));
50410 continue;
50411 }
50412
50413 DUK_ASSERT(DUK_HSTRING_HAS_ARRIDX(key)); /* XXX: macro checks for array index flag, which is unnecessary here */
50414 arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
50415 DUK_ASSERT(arr_idx != DUK__NO_ARRAY_INDEX);
50416 DUK_ASSERT(arr_idx < old_len); /* consistency requires this */
50417
50418 if (arr_idx < target_len) {
50419 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key is array index %ld, below target_len",
50420 (long) i, (long) arr_idx));
50421 continue;
50422 }
50423 DUK_ASSERT(force_flag || DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(thr->heap, obj, i)); /* stage 1 guarantees */
50424
50425 DUK_DDD(DUK_DDDPRINT("delete entry index %ld: key is array index %ld",
50426 (long) i, (long) arr_idx));
50427
50428 /*
50429 * Slow delete, but we don't care as we're already in a very slow path.
50430 * The delete always succeeds: key has no exotic behavior, property
50431 * is configurable, and no resize occurs.
50432 */
50433 rc = duk_hobject_delprop_raw(thr, obj, key, force_flag ? DUK_DELPROP_FLAG_FORCE : 0);
50434 DUK_UNREF(rc);
50435 DUK_ASSERT(rc != 0);
50436 }
50437
50438 /* stage 3: update length (done by caller), decide return code */
50439
50440 DUK_DDD(DUK_DDDPRINT("array length write, no array part, stage 3: update length (done by caller)"));
50441
50442 *out_result_len = target_len;
50443
50444 if (target_len == new_len) {
50445 DUK_DDD(DUK_DDDPRINT("target_len matches new_len, return success"));
50446 return 1;
50447 }
50448 DUK_DDD(DUK_DDDPRINT("target_len does not match new_len (some entry prevented "
50449 "full length adjustment), return error"));
50450 return 0;
50451 }
50452
50453 DUK_UNREACHABLE();
50454}
50455
50456/* XXX: is valstack top best place for argument? */
50457DUK_LOCAL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hobject *obj) {
50458 duk_context *ctx = (duk_context *) thr;
50459 duk_propdesc desc;
50460 duk_uint32_t old_len;
50461 duk_uint32_t new_len;
50462 duk_uint32_t result_len;
50463 duk_tval *tv;
50464 duk_bool_t rc;
50465
50466 DUK_DDD(DUK_DDDPRINT("handling a put operation to array 'length' exotic property, "
50467 "new val: %!T",
50468 (duk_tval *) duk_get_tval(ctx, -1)));
50469
50470 DUK_ASSERT(thr != NULL);
50471 DUK_ASSERT(ctx != NULL);
50472 DUK_ASSERT(obj != NULL);
50473
50474 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
50475
50476 DUK_ASSERT(duk_is_valid_index(ctx, -1));
50477
50478 /*
50479 * Get old and new length
50480 */
50481
50482 old_len = duk__get_old_array_length(thr, obj, &desc);
50483 duk_dup(ctx, -1); /* [in_val in_val] */
50484 new_len = duk__to_new_array_length_checked(thr); /* -> [in_val] */
50485 DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld", (long) old_len, (long) new_len));
50486
50487 /*
50488 * Writability check
50489 */
50490
50491 if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
50492 DUK_DDD(DUK_DDDPRINT("length is not writable, fail"));
50493 return 0;
50494 }
50495
50496 /*
50497 * New length not lower than old length => no changes needed
50498 * (not even array allocation).
50499 */
50500
50501 if (new_len >= old_len) {
50502 DUK_DDD(DUK_DDDPRINT("new length is higher than old length, just update length, no deletions"));
50503
50504 DUK_ASSERT(desc.e_idx >= 0);
50505 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, desc.e_idx));
50506 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, desc.e_idx);
50507 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
50508 /* no decref needed for a number */
7c673cae 50509 DUK_TVAL_SET_FASTINT_U32(tv, new_len);
7c673cae
FG
50510 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
50511 return 1;
50512 }
50513
50514 DUK_DDD(DUK_DDDPRINT("new length is lower than old length, probably must delete entries"));
50515
50516 /*
50517 * New length lower than old length => delete elements, then
50518 * update length.
50519 *
50520 * Note: even though a bunch of elements have been deleted, the 'desc' is
50521 * still valid as properties haven't been resized (and entries compacted).
50522 */
50523
50524 rc = duk__handle_put_array_length_smaller(thr, obj, old_len, new_len, 0 /*force_flag*/, &result_len);
50525 DUK_ASSERT(result_len >= new_len && result_len <= old_len);
50526
50527 DUK_ASSERT(desc.e_idx >= 0);
50528 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, desc.e_idx));
50529 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, desc.e_idx);
50530 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
50531 /* no decref needed for a number */
7c673cae 50532 DUK_TVAL_SET_FASTINT_U32(tv, result_len);
7c673cae
FG
50533 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
50534
50535 /* XXX: shrink array allocation or entries compaction here? */
50536
50537 return rc;
50538}
50539
50540/*
50541 * PUTPROP: Ecmascript property write.
50542 *
50543 * Unlike Ecmascript primitive which returns nothing, returns 1 to indicate
50544 * success and 0 to indicate failure (assuming throw is not set).
50545 *
50546 * This is an extremely tricky function. Some examples:
50547 *
50548 * * Currently a decref may trigger a GC, which may compact an object's
50549 * property allocation. Consequently, any entry indices (e_idx) will
50550 * be potentially invalidated by a decref.
50551 *
50552 * * Exotic behaviors (strings, arrays, arguments object) require,
50553 * among other things:
50554 *
50555 * - Preprocessing before and postprocessing after an actual property
50556 * write. For example, array index write requires pre-checking the
50557 * array 'length' property for access control, and may require an
50558 * array 'length' update after the actual write has succeeded (but
50559 * not if it fails).
50560 *
50561 * - Deletion of multiple entries, as a result of array 'length' write.
50562 *
50563 * * Input values are taken as pointers which may point to the valstack.
50564 * If valstack is resized because of the put (this may happen at least
50565 * when the array part is abandoned), the pointers can be invalidated.
50566 * (We currently make a copy of all of the input values to avoid issues.)
50567 */
50568
50569DUK_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) {
50570 duk_context *ctx = (duk_context *) thr;
50571 duk_tval tv_obj_copy;
50572 duk_tval tv_key_copy;
50573 duk_tval tv_val_copy;
50574 duk_hobject *orig = NULL; /* NULL if tv_obj is primitive */
50575 duk_hobject *curr;
50576 duk_hstring *key = NULL;
50577 duk_propdesc desc;
50578 duk_tval *tv;
50579 duk_uint32_t arr_idx;
50580 duk_bool_t rc;
50581 duk_int_t e_idx;
50582 duk_uint_t sanity;
50583 duk_uint32_t new_array_length = 0; /* 0 = no update */
50584
50585 DUK_DDD(DUK_DDDPRINT("putprop: thr=%p, obj=%p, key=%p, val=%p, throw=%ld "
50586 "(obj -> %!T, key -> %!T, val -> %!T)",
50587 (void *) thr, (void *) tv_obj, (void *) tv_key, (void *) tv_val,
50588 (long) throw_flag, (duk_tval *) tv_obj, (duk_tval *) tv_key, (duk_tval *) tv_val));
50589
50590 DUK_ASSERT(thr != NULL);
50591 DUK_ASSERT(thr->heap != NULL);
50592 DUK_ASSERT(ctx != NULL);
50593 DUK_ASSERT(tv_obj != NULL);
50594 DUK_ASSERT(tv_key != NULL);
50595 DUK_ASSERT(tv_val != NULL);
50596
50597 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
50598
50599 /*
50600 * Make a copy of tv_obj, tv_key, and tv_val to avoid any issues of
50601 * them being invalidated by a valstack resize.
50602 *
50603 * XXX: this is an overkill for some paths, so optimize this later
50604 * (or maybe switch to a stack arguments model entirely).
50605 */
50606
50607 DUK_TVAL_SET_TVAL(&tv_obj_copy, tv_obj);
50608 DUK_TVAL_SET_TVAL(&tv_key_copy, tv_key);
50609 DUK_TVAL_SET_TVAL(&tv_val_copy, tv_val);
50610 tv_obj = &tv_obj_copy;
50611 tv_key = &tv_key_copy;
50612 tv_val = &tv_val_copy;
50613
50614 /*
50615 * Coercion and fast path processing.
50616 */
50617
50618 switch (DUK_TVAL_GET_TAG(tv_obj)) {
50619 case DUK_TAG_UNDEFINED:
50620 case DUK_TAG_NULL: {
50621 /* Note: unconditional throw */
50622 DUK_DDD(DUK_DDDPRINT("base object is undefined or null -> reject (object=%!iT)",
50623 (duk_tval *) tv_obj));
11fdf7f2
TL
50624#if defined(DUK_USE_PARANOID_ERRORS)
50625 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
50626#else
50627 DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot write property %s of %s",
50628 duk_push_string_tval_readable(ctx, tv_key), duk_push_string_tval_readable(ctx, tv_obj));
50629#endif
7c673cae
FG
50630 return 0;
50631 }
50632
50633 case DUK_TAG_BOOLEAN: {
50634 DUK_DDD(DUK_DDDPRINT("base object is a boolean, start lookup from boolean prototype"));
50635 curr = thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE];
50636 break;
50637 }
50638
50639 case DUK_TAG_STRING: {
50640 duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj);
50641
50642 /*
50643 * Note: currently no fast path for array index writes.
50644 * They won't be possible anyway as strings are immutable.
50645 */
50646
50647 DUK_ASSERT(key == NULL);
50648 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
50649 DUK_ASSERT(key != NULL);
50650
50651 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
50652 goto fail_not_writable;
50653 }
50654
50655 if (arr_idx != DUK__NO_ARRAY_INDEX &&
50656 arr_idx < DUK_HSTRING_GET_CHARLEN(h)) {
50657 goto fail_not_writable;
50658 }
50659
50660 DUK_DDD(DUK_DDDPRINT("base object is a string, start lookup from string prototype"));
50661 curr = thr->builtins[DUK_BIDX_STRING_PROTOTYPE];
50662 goto lookup; /* avoid double coercion */
50663 }
50664
50665 case DUK_TAG_OBJECT: {
50666 orig = DUK_TVAL_GET_OBJECT(tv_obj);
50667 DUK_ASSERT(orig != NULL);
50668
11fdf7f2
TL
50669#if defined(DUK_USE_ROM_OBJECTS)
50670 /* With this check in place fast paths won't need read-only
50671 * object checks. This is technically incorrect if there are
50672 * setters that cause no writes to ROM objects, but current
50673 * built-ins don't have such setters.
50674 */
50675 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) orig)) {
50676 DUK_DD(DUK_DDPRINT("attempt to putprop on read-only target object"));
50677 goto fail_not_writable_no_pop; /* Must avoid duk_pop() in exit path */
50678 }
50679#endif
50680
7c673cae
FG
50681 /* The fast path for array property put is not fully compliant:
50682 * If one places conflicting number-indexed properties into
50683 * Array.prototype (for example, a non-writable Array.prototype[7])
50684 * the fast path will incorrectly ignore them.
50685 *
50686 * This fast path could be made compliant by falling through
11fdf7f2
TL
50687 * to the slow path if the previous value was UNUSED. This would
50688 * also remove the need to check for extensibility. Right now a
50689 * non-extensible array is slower than an extensible one as far
50690 * as writes are concerned.
7c673cae
FG
50691 *
50692 * The fast path behavior is documented in more detail here:
50693 * tests/ecmascript/test-misc-array-fast-write.js
50694 */
50695
50696 if (duk__putprop_shallow_fastpath_array_tval(thr, orig, tv_key, tv_val, &desc) != 0) {
50697 DUK_DDD(DUK_DDDPRINT("array fast path success"));
50698 return 1;
50699 }
50700
50701 if (duk__putprop_fastpath_bufobj_tval(thr, orig, tv_key, tv_val) != 0) {
50702 DUK_DDD(DUK_DDDPRINT("base is bufobj, key is a number, bufferobject fast path"));
50703 return 1;
50704 }
50705
50706#if defined(DUK_USE_ES6_PROXY)
50707 if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(orig))) {
50708 duk_hobject *h_target;
50709 duk_bool_t tmp_bool;
50710
50711 if (duk__proxy_check_prop(thr, orig, DUK_STRIDX_SET, tv_key, &h_target)) {
50712 /* -> [ ... trap handler ] */
50713 DUK_DDD(DUK_DDDPRINT("-> proxy object 'set' for key %!T", (duk_tval *) tv_key));
50714 duk_push_hobject(ctx, h_target); /* target */
50715 duk_push_tval(ctx, tv_key); /* P */
50716 duk_push_tval(ctx, tv_val); /* V */
50717 duk_push_tval(ctx, tv_obj); /* Receiver: Proxy object */
50718 duk_call_method(ctx, 4 /*nargs*/);
50719 tmp_bool = duk_to_boolean(ctx, -1);
50720 duk_pop(ctx);
50721 if (!tmp_bool) {
50722 goto fail_proxy_rejected;
50723 }
50724
50725 /* Target object must be checked for a conflicting
50726 * non-configurable property.
50727 */
50728 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
50729 DUK_ASSERT(key != NULL);
50730
11fdf7f2 50731 if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
7c673cae
FG
50732 duk_tval *tv_targ = duk_require_tval(ctx, -1);
50733 duk_bool_t datadesc_reject;
50734 duk_bool_t accdesc_reject;
50735
50736 DUK_DDD(DUK_DDDPRINT("proxy 'set': target has matching property %!O, check for "
50737 "conflicting property; tv_val=%!T, tv_targ=%!T, desc.flags=0x%08lx, "
50738 "desc.get=%p, desc.set=%p",
50739 (duk_heaphdr *) key, (duk_tval *) tv_val, (duk_tval *) tv_targ,
50740 (unsigned long) desc.flags,
50741 (void *) desc.get, (void *) desc.set));
50742
50743 datadesc_reject = !(desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
50744 !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) &&
50745 !(desc.flags & DUK_PROPDESC_FLAG_WRITABLE) &&
50746 !duk_js_samevalue(tv_val, tv_targ);
50747 accdesc_reject = (desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
50748 !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) &&
50749 (desc.set == NULL);
50750 if (datadesc_reject || accdesc_reject) {
11fdf7f2 50751 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
7c673cae
FG
50752 }
50753
50754 duk_pop_2(ctx);
50755 } else {
50756 duk_pop(ctx);
50757 }
50758 return 1; /* success */
50759 }
50760
50761 orig = h_target; /* resume write to target */
50762 DUK_TVAL_SET_OBJECT(tv_obj, orig);
50763 }
50764#endif /* DUK_USE_ES6_PROXY */
50765
50766 curr = orig;
50767 break;
50768 }
50769
50770 case DUK_TAG_BUFFER: {
50771 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj);
50772 duk_int_t pop_count = 0;
50773
50774 /*
50775 * Because buffer values may be looped over and read/written
50776 * from, an array index fast path is important.
50777 */
50778
50779#if defined(DUK_USE_FASTINT)
50780 if (DUK_TVAL_IS_FASTINT(tv_key)) {
50781 arr_idx = duk__tval_fastint_to_arr_idx(tv_key);
50782 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path fastint; arr_idx %ld", (long) arr_idx));
50783 pop_count = 0;
50784 } else
50785#endif
50786 if (DUK_TVAL_IS_NUMBER(tv_key)) {
50787 arr_idx = duk__tval_number_to_arr_idx(tv_key);
50788 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path number; arr_idx %ld", (long) arr_idx));
50789 pop_count = 0;
50790 } else {
50791 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
50792 DUK_ASSERT(key != NULL);
50793 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
50794 "coercion key is %!T, arr_idx %ld",
50795 (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
50796 pop_count = 1;
50797 }
50798
50799 if (arr_idx != DUK__NO_ARRAY_INDEX &&
50800 arr_idx < DUK_HBUFFER_GET_SIZE(h)) {
50801 duk_uint8_t *data;
50802 DUK_DDD(DUK_DDDPRINT("writing to buffer data at index %ld", (long) arr_idx));
50803 data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h);
50804
50805 /* XXX: duk_to_int() ensures we'll get 8 lowest bits as
50806 * as input is within duk_int_t range (capped outside it).
50807 */
50808#if defined(DUK_USE_FASTINT)
50809 /* Buffer writes are often integers. */
50810 if (DUK_TVAL_IS_FASTINT(tv_val)) {
50811 data[arr_idx] = (duk_uint8_t) DUK_TVAL_GET_FASTINT_U32(tv_val);
50812 }
50813 else
50814#endif
50815 {
50816 duk_push_tval(ctx, tv_val);
50817 data[arr_idx] = (duk_uint8_t) duk_to_uint32(ctx, -1);
50818 pop_count++;
50819 }
50820
50821 duk_pop_n(ctx, pop_count);
50822 DUK_DDD(DUK_DDDPRINT("result: success (buffer data write)"));
50823 return 1;
50824 }
50825
50826 if (pop_count == 0) {
50827 /* This is a pretty awkward control flow, but we need to recheck the
50828 * key coercion here.
50829 */
50830 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
50831 DUK_ASSERT(key != NULL);
50832 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
50833 "coercion key is %!T, arr_idx %ld",
50834 (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
50835 }
50836
50837 if (key == DUK_HTHREAD_STRING_LENGTH(thr) ||
50838 key == DUK_HTHREAD_STRING_BYTE_LENGTH(thr) ||
50839 key == DUK_HTHREAD_STRING_BYTE_OFFSET(thr) ||
50840 key == DUK_HTHREAD_STRING_BYTES_PER_ELEMENT(thr)) {
50841 goto fail_not_writable;
50842 }
50843
50844 DUK_DDD(DUK_DDDPRINT("base object is a buffer, start lookup from buffer prototype"));
50845 curr = thr->builtins[DUK_BIDX_BUFFER_PROTOTYPE];
50846 goto lookup; /* avoid double coercion */
50847 }
50848
50849 case DUK_TAG_POINTER: {
50850 DUK_DDD(DUK_DDDPRINT("base object is a pointer, start lookup from pointer prototype"));
50851 curr = thr->builtins[DUK_BIDX_POINTER_PROTOTYPE];
50852 break;
50853 }
50854
50855 case DUK_TAG_LIGHTFUNC: {
50856 /* All lightfunc own properties are non-writable and the lightfunc
50857 * is considered non-extensible. However, the write may be captured
50858 * by an inherited setter which means we can't stop the lookup here.
50859 */
50860
50861 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
50862
50863 if (duk__key_is_lightfunc_ownprop(thr, key)) {
50864 goto fail_not_writable;
50865 }
50866
50867 DUK_DDD(DUK_DDDPRINT("base object is a lightfunc, start lookup from function prototype"));
50868 curr = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
50869 goto lookup; /* avoid double coercion */
50870 }
50871
50872#if defined(DUK_USE_FASTINT)
50873 case DUK_TAG_FASTINT:
50874#endif
50875 default: {
50876 /* number */
50877 DUK_DDD(DUK_DDDPRINT("base object is a number, start lookup from number prototype"));
50878 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_obj));
50879 curr = thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE];
50880 break;
50881 }
50882 }
50883
50884 DUK_ASSERT(key == NULL);
50885 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
50886 DUK_ASSERT(key != NULL);
50887
50888 lookup:
50889
50890 /*
50891 * Check whether the property already exists in the prototype chain.
50892 * Note that the actual write goes into the original base object
50893 * (except if an accessor property captures the write).
50894 */
50895
50896 /* [key] */
50897
50898 DUK_ASSERT(curr != NULL);
50899 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
50900 do {
11fdf7f2 50901 if (!duk__get_own_propdesc_raw(thr, curr, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */
7c673cae
FG
50902 goto next_in_chain;
50903 }
50904
50905 if (desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
50906 /*
50907 * Found existing accessor property (own or inherited).
50908 * Call setter with 'this' set to orig, and value as the only argument.
11fdf7f2 50909 * Setter calls are OK even for ROM objects.
7c673cae
FG
50910 *
50911 * Note: no exotic arguments object behavior, because [[Put]] never
50912 * calls [[DefineOwnProperty]] (E5 Section 8.12.5, step 5.b).
50913 */
50914
50915 duk_hobject *setter;
50916
50917 DUK_DD(DUK_DDPRINT("put to an own or inherited accessor, calling setter"));
50918
50919 setter = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, curr, desc.e_idx);
50920 if (!setter) {
50921 goto fail_no_setter;
50922 }
50923 duk_push_hobject(ctx, setter);
50924 duk_push_tval(ctx, tv_obj); /* note: original, uncoerced base */
50925 duk_push_tval(ctx, tv_val); /* [key setter this val] */
50926#ifdef DUK_USE_NONSTD_SETTER_KEY_ARGUMENT
50927 duk_dup(ctx, -4);
50928 duk_call_method(ctx, 2); /* [key setter this val key] -> [key retval] */
50929#else
50930 duk_call_method(ctx, 1); /* [key setter this val] -> [key retval] */
50931#endif
50932 duk_pop(ctx); /* ignore retval -> [key] */
50933 goto success_no_arguments_exotic;
50934 }
50935
50936 if (orig == NULL) {
50937 /*
50938 * Found existing own or inherited plain property, but original
50939 * base is a primitive value.
50940 */
50941 DUK_DD(DUK_DDPRINT("attempt to create a new property in a primitive base object"));
50942 goto fail_base_primitive;
50943 }
50944
50945 if (curr != orig) {
50946 /*
50947 * Found existing inherited plain property.
50948 * Do an access control check, and if OK, write
50949 * new property to 'orig'.
50950 */
50951 if (!DUK_HOBJECT_HAS_EXTENSIBLE(orig)) {
50952 DUK_DD(DUK_DDPRINT("found existing inherited plain property, but original object is not extensible"));
50953 goto fail_not_extensible;
50954 }
50955 if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
50956 DUK_DD(DUK_DDPRINT("found existing inherited plain property, original object is extensible, but inherited property is not writable"));
50957 goto fail_not_writable;
50958 }
50959 DUK_DD(DUK_DDPRINT("put to new property, object extensible, inherited property found and is writable"));
50960 goto create_new;
50961 } else {
50962 /*
50963 * Found existing own (non-inherited) plain property.
50964 * Do an access control check and update in place.
50965 */
50966
50967 if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
50968 DUK_DD(DUK_DDPRINT("found existing own (non-inherited) plain property, but property is not writable"));
50969 goto fail_not_writable;
50970 }
50971 if (desc.flags & DUK_PROPDESC_FLAG_VIRTUAL) {
50972 DUK_DD(DUK_DDPRINT("found existing own (non-inherited) virtual property, property is writable"));
50973 if (DUK_HOBJECT_IS_BUFFEROBJECT(curr)) {
50974 duk_hbufferobject *h_bufobj;
50975 duk_uint_t byte_off;
50976 duk_small_uint_t elem_size;
50977
50978 h_bufobj = (duk_hbufferobject *) curr;
50979 DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
50980
50981 DUK_DD(DUK_DDPRINT("writable virtual property is in buffer object"));
50982
50983 /* Careful with wrapping: arr_idx upshift may easily wrap, whereas
50984 * length downshift won't.
50985 */
50986 if (arr_idx < (h_bufobj->length >> h_bufobj->shift)) {
50987 duk_uint8_t *data;
50988 DUK_DDD(DUK_DDDPRINT("writing to buffer data at index %ld", (long) arr_idx));
50989
50990 DUK_ASSERT(arr_idx != DUK__NO_ARRAY_INDEX); /* index/length check guarantees */
50991 byte_off = arr_idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */
50992 elem_size = 1 << h_bufobj->shift;
50993
50994 /* Coerce to number before validating pointers etc so that the
50995 * number coercions in duk_hbufferobject_validated_write() are
50996 * guaranteed to be side effect free and not invalidate the
50997 * pointer checks we do here.
50998 */
50999 duk_push_tval(ctx, tv_val);
51000 duk_to_number(ctx, -1);
51001
51002 if (h_bufobj->buf != NULL && DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
51003 data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
51004 duk_hbufferobject_validated_write(ctx, h_bufobj, data, elem_size);
51005 } else {
51006 DUK_D(DUK_DPRINT("bufferobject access out of underlying buffer, ignoring (write skipped)"));
51007 }
51008 duk_pop(ctx);
51009 goto success_no_arguments_exotic;
51010 }
51011 }
51012
51013 goto fail_internal; /* should not happen */
51014 }
51015 DUK_DD(DUK_DDPRINT("put to existing own plain property, property is writable"));
51016 goto update_old;
51017 }
51018 DUK_UNREACHABLE();
51019
51020 next_in_chain:
51021 /* XXX: option to pretend property doesn't exist if sanity limit is
51022 * hit might be useful.
51023 */
51024 if (sanity-- == 0) {
11fdf7f2 51025 DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
7c673cae
FG
51026 }
51027 curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
51028 } while (curr);
51029
51030 /*
51031 * Property not found in prototype chain.
51032 */
51033
51034 DUK_DDD(DUK_DDDPRINT("property not found in prototype chain"));
51035
51036 if (orig == NULL) {
51037 DUK_DD(DUK_DDPRINT("attempt to create a new property in a primitive base object"));
51038 goto fail_base_primitive;
51039 }
51040
51041 if (!DUK_HOBJECT_HAS_EXTENSIBLE(orig)) {
51042 DUK_DD(DUK_DDPRINT("put to a new property (not found in prototype chain), but original object not extensible"));
51043 goto fail_not_extensible;
51044 }
51045
51046 goto create_new;
51047
51048 update_old:
51049
51050 /*
51051 * Update an existing property of the base object.
51052 */
51053
51054 /* [key] */
51055
51056 DUK_DDD(DUK_DDDPRINT("update an existing property of the original object"));
51057
51058 DUK_ASSERT(orig != NULL);
11fdf7f2
TL
51059#if defined(DUK_USE_ROM_OBJECTS)
51060 /* This should not happen because DUK_TAG_OBJECT case checks
51061 * for this already, but check just in case.
51062 */
51063 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) orig)) {
51064 goto fail_not_writable;
51065 }
51066#endif
7c673cae
FG
51067
51068 /* Although there are writable virtual properties (e.g. plain buffer
51069 * and buffer object number indices), they are handled before we come
51070 * here.
51071 */
51072 DUK_ASSERT((desc.flags & DUK_PROPDESC_FLAG_VIRTUAL) == 0);
51073 DUK_ASSERT(desc.a_idx >= 0 || desc.e_idx >= 0);
51074
51075 if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(orig) &&
51076 key == DUK_HTHREAD_STRING_LENGTH(thr)) {
51077 /*
51078 * Write to 'length' of an array is a very complex case
51079 * handled in a helper which updates both the array elements
51080 * and writes the new 'length'. The write may result in an
51081 * unconditional RangeError or a partial write (indicated
51082 * by a return code).
51083 *
51084 * Note: the helper has an unnecessary writability check
51085 * for 'length', we already know it is writable.
51086 */
51087
51088 DUK_DDD(DUK_DDDPRINT("writing existing 'length' property to array exotic, invoke complex helper"));
51089
51090 /* XXX: the helper currently assumes stack top contains new
51091 * 'length' value and the whole calling convention is not very
51092 * compatible with what we need.
51093 */
51094
51095 duk_push_tval(ctx, tv_val); /* [key val] */
51096 rc = duk__handle_put_array_length(thr, orig);
51097 duk_pop(ctx); /* [key val] -> [key] */
51098 if (!rc) {
51099 goto fail_array_length_partial;
51100 }
51101
51102 /* key is 'length', cannot match argument exotic behavior */
51103 goto success_no_arguments_exotic;
51104 }
51105
51106 if (desc.e_idx >= 0) {
7c673cae
FG
51107 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, orig, desc.e_idx);
51108 DUK_DDD(DUK_DDDPRINT("previous entry value: %!iT", (duk_tval *) tv));
11fdf7f2 51109 DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val); /* side effects */
7c673cae
FG
51110 /* don't touch property attributes or hash part */
51111 DUK_DD(DUK_DDPRINT("put to an existing entry at index %ld -> new value %!iT",
51112 (long) desc.e_idx, (duk_tval *) tv));
51113 } else {
51114 /* Note: array entries are always writable, so the writability check
51115 * above is pointless for them. The check could be avoided with some
51116 * refactoring but is probably not worth it.
51117 */
7c673cae
FG
51118
51119 DUK_ASSERT(desc.a_idx >= 0);
51120 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, orig, desc.a_idx);
51121 DUK_DDD(DUK_DDDPRINT("previous array value: %!iT", (duk_tval *) tv));
11fdf7f2 51122 DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val); /* side effects */
7c673cae
FG
51123 DUK_DD(DUK_DDPRINT("put to an existing array entry at index %ld -> new value %!iT",
51124 (long) desc.a_idx, (duk_tval *) tv));
51125 }
51126
51127 /* Regardless of whether property is found in entry or array part,
51128 * it may have arguments exotic behavior (array indices may reside
51129 * in entry part for abandoned / non-existent array parts).
51130 */
51131 goto success_with_arguments_exotic;
51132
51133 create_new:
51134
51135 /*
51136 * Create a new property in the original object.
51137 *
51138 * Exotic properties need to be reconsidered here from a write
51139 * perspective (not just property attributes perspective).
51140 * However, the property does not exist in the object already,
51141 * so this limits the kind of exotic properties that apply.
51142 */
51143
51144 /* [key] */
51145
51146 DUK_DDD(DUK_DDDPRINT("create new property to original object"));
51147
51148 DUK_ASSERT(orig != NULL);
51149
11fdf7f2
TL
51150#if defined(DUK_USE_ROM_OBJECTS)
51151 /* This should not happen because DUK_TAG_OBJECT case checks
51152 * for this already, but check just in case.
51153 */
51154 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) orig)) {
51155 goto fail_not_writable;
51156 }
51157#endif
51158
7c673cae
FG
51159 /* Not possible because array object 'length' is present
51160 * from its creation and cannot be deleted, and is thus
51161 * caught as an existing property above.
51162 */
51163 DUK_ASSERT(!(DUK_HOBJECT_HAS_EXOTIC_ARRAY(orig) &&
51164 key == DUK_HTHREAD_STRING_LENGTH(thr)));
51165
51166 if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(orig) &&
51167 arr_idx != DUK__NO_ARRAY_INDEX) {
51168 /* automatic length update */
51169 duk_uint32_t old_len;
51170
51171 old_len = duk__get_old_array_length(thr, orig, &desc);
51172
51173 if (arr_idx >= old_len) {
51174 DUK_DDD(DUK_DDDPRINT("write new array entry requires length update "
51175 "(arr_idx=%ld, old_len=%ld)",
51176 (long) arr_idx, (long) old_len));
51177
51178 if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
51179 DUK_DD(DUK_DDPRINT("attempt to extend array, but array 'length' is not writable"));
51180 goto fail_not_writable;
51181 }
51182
51183 /* Note: actual update happens once write has been completed
51184 * without error below. The write should always succeed
51185 * from a specification viewpoint, but we may e.g. run out
51186 * of memory. It's safer in this order.
51187 */
51188
51189 DUK_ASSERT(arr_idx != 0xffffffffUL);
51190 new_array_length = arr_idx + 1; /* flag for later write */
51191 } else {
51192 DUK_DDD(DUK_DDDPRINT("write new array entry does not require length update "
51193 "(arr_idx=%ld, old_len=%ld)",
51194 (long) arr_idx, (long) old_len));
51195 }
51196 }
51197
51198 /* write_to_array_part: */
51199
51200 /*
51201 * Write to array part?
51202 *
51203 * Note: array abandonding requires a property resize which uses
51204 * 'rechecks' valstack for temporaries and may cause any existing
51205 * valstack pointers to be invalidated. To protect against this,
51206 * tv_obj, tv_key, and tv_val are copies of the original inputs.
51207 */
51208
51209 if (arr_idx != DUK__NO_ARRAY_INDEX &&
51210 DUK_HOBJECT_HAS_ARRAY_PART(orig)) {
51211 if (arr_idx < DUK_HOBJECT_GET_ASIZE(orig)) {
51212 goto no_array_growth;
51213 }
51214
51215 /*
51216 * Array needs to grow, but we don't want it becoming too sparse.
51217 * If it were to become sparse, abandon array part, moving all
51218 * array entries into the entries part (for good).
51219 *
51220 * Since we don't keep track of actual density (used vs. size) of
51221 * the array part, we need to estimate somehow. The check is made
51222 * in two parts:
51223 *
51224 * - Check whether the resize need is small compared to the
51225 * current size (relatively); if so, resize without further
51226 * checking (essentially we assume that the original part is
51227 * "dense" so that the result would be dense enough).
51228 *
51229 * - Otherwise, compute the resize using an actual density
51230 * measurement based on counting the used array entries.
51231 */
51232
51233 DUK_DDD(DUK_DDDPRINT("write to new array requires array resize, decide whether to do a "
51234 "fast resize without abandon check (arr_idx=%ld, old_size=%ld)",
51235 (long) arr_idx, (long) DUK_HOBJECT_GET_ASIZE(orig)));
51236
51237 if (duk__abandon_array_slow_check_required(arr_idx, DUK_HOBJECT_GET_ASIZE(orig))) {
51238 duk_uint32_t old_used;
51239 duk_uint32_t old_size;
51240
51241 DUK_DDD(DUK_DDDPRINT("=> fast check is NOT OK, do slow check for array abandon"));
51242
51243 duk__compute_a_stats(thr, orig, &old_used, &old_size);
51244
51245 DUK_DDD(DUK_DDDPRINT("abandon check, array stats: old_used=%ld, old_size=%ld, arr_idx=%ld",
51246 (long) old_used, (long) old_size, (long) arr_idx));
51247
51248 /* Note: intentionally use approximations to shave a few instructions:
51249 * a_used = old_used (accurate: old_used + 1)
51250 * a_size = arr_idx (accurate: arr_idx + 1)
51251 */
51252 if (duk__abandon_array_density_check(old_used, arr_idx)) {
51253 DUK_DD(DUK_DDPRINT("write to new array entry beyond current length, "
51254 "decided to abandon array part (would become too sparse)"));
51255
51256 /* abandoning requires a props allocation resize and
51257 * 'rechecks' the valstack, invalidating any existing
51258 * valstack value pointers!
51259 */
51260 duk__abandon_array_checked(thr, orig);
51261 DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(orig));
51262
51263 goto write_to_entry_part;
51264 }
51265
51266 DUK_DDD(DUK_DDDPRINT("=> decided to keep array part"));
51267 } else {
51268 DUK_DDD(DUK_DDDPRINT("=> fast resize is OK"));
51269 }
51270
51271 DUK_DD(DUK_DDPRINT("write to new array entry beyond current length, "
51272 "decided to extend current allocation"));
51273
51274 duk__grow_props_for_array_item(thr, orig, arr_idx);
51275
51276 no_array_growth:
51277
51278 /* Note: assume array part is comprehensive, so that either
51279 * the write goes to the array part, or we've abandoned the
51280 * array above (and will not come here).
51281 */
51282
51283 DUK_ASSERT(DUK_HOBJECT_HAS_ARRAY_PART(orig));
51284 DUK_ASSERT(arr_idx < DUK_HOBJECT_GET_ASIZE(orig));
51285
51286 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, orig, arr_idx);
51287 /* prev value must be unused, no decref */
11fdf7f2 51288 DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv));
7c673cae
FG
51289 DUK_TVAL_SET_TVAL(tv, tv_val);
51290 DUK_TVAL_INCREF(thr, tv);
51291 DUK_DD(DUK_DDPRINT("put to new array entry: %ld -> %!T",
51292 (long) arr_idx, (duk_tval *) tv));
51293
51294 /* Note: array part values are [[Writable]], [[Enumerable]],
51295 * and [[Configurable]] which matches the required attributes
51296 * here.
51297 */
51298 goto entry_updated;
51299 }
51300
51301 write_to_entry_part:
51302
51303 /*
51304 * Write to entry part
51305 */
51306
51307 /* entry allocation updates hash part and increases the key
51308 * refcount; may need a props allocation resize but doesn't
51309 * 'recheck' the valstack.
51310 */
51311 e_idx = duk__alloc_entry_checked(thr, orig, key);
51312 DUK_ASSERT(e_idx >= 0);
51313
51314 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, orig, e_idx);
51315 /* prev value can be garbage, no decref */
51316 DUK_TVAL_SET_TVAL(tv, tv_val);
51317 DUK_TVAL_INCREF(thr, tv);
51318 DUK_HOBJECT_E_SET_FLAGS(thr->heap, orig, e_idx, DUK_PROPDESC_FLAGS_WEC);
51319 goto entry_updated;
51320
51321 entry_updated:
51322
51323 /*
51324 * Possible pending array length update, which must only be done
51325 * if the actual entry write succeeded.
51326 */
51327
51328 if (new_array_length > 0) {
51329 /*
51330 * Note: zero works as a "no update" marker because the new length
51331 * can never be zero after a new property is written.
51332 *
51333 * Note: must re-lookup because calls above (e.g. duk__alloc_entry_checked())
51334 * may realloc and compact properties and hence change e_idx.
51335 */
51336
51337 DUK_DDD(DUK_DDDPRINT("write successful, pending array length update to: %ld",
51338 (long) new_array_length));
51339
11fdf7f2 51340 rc = duk__get_own_propdesc_raw(thr, orig, DUK_HTHREAD_STRING_LENGTH(thr), DUK__NO_ARRAY_INDEX, &desc, 0 /*flags*/); /* don't push value */
7c673cae
FG
51341 DUK_UNREF(rc);
51342 DUK_ASSERT(rc != 0);
51343 DUK_ASSERT(desc.e_idx >= 0);
51344
51345 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, orig, desc.e_idx);
51346 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
51347 /* no need for decref/incref because value is a number */
7c673cae 51348 DUK_TVAL_SET_FASTINT_U32(tv, new_array_length);
7c673cae
FG
51349 }
51350
51351 /*
51352 * Arguments exotic behavior not possible for new properties: all
51353 * magically bound properties are initially present in the arguments
51354 * object, and if they are deleted, the binding is also removed from
51355 * parameter map.
51356 */
51357
51358 goto success_no_arguments_exotic;
51359
51360 success_with_arguments_exotic:
51361
51362 /*
51363 * Arguments objects have exotic [[DefineOwnProperty]] which updates
51364 * the internal 'map' of arguments for writes to currently mapped
51365 * arguments. More conretely, writes to mapped arguments generate
51366 * a write to a bound variable.
51367 *
51368 * The [[Put]] algorithm invokes [[DefineOwnProperty]] for existing
51369 * data properties and new properties, but not for existing accessors.
51370 * Hence, in E5 Section 10.6 ([[DefinedOwnProperty]] algorithm), we
51371 * have a Desc with 'Value' (and possibly other properties too), and
51372 * we end up in step 5.b.i.
51373 */
51374
51375 if (arr_idx != DUK__NO_ARRAY_INDEX &&
51376 DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(orig)) {
51377 /* Note: only numbered indices are relevant, so arr_idx fast reject
51378 * is good (this is valid unless there are more than 4**32-1 arguments).
51379 */
51380
51381 DUK_DDD(DUK_DDDPRINT("putprop successful, arguments exotic behavior needed"));
51382
51383 /* Note: we can reuse 'desc' here */
51384
51385 /* XXX: top of stack must contain value, which helper doesn't touch,
51386 * rework to use tv_val directly?
51387 */
51388
51389 duk_push_tval(ctx, tv_val);
51390 (void) duk__check_arguments_map_for_put(thr, orig, key, &desc, throw_flag);
51391 duk_pop(ctx);
51392 }
51393 /* fall thru */
51394
51395 success_no_arguments_exotic:
51396 /* shared exit path now */
51397 DUK_DDD(DUK_DDDPRINT("result: success"));
51398 duk_pop(ctx); /* remove key */
51399 return 1;
51400
11fdf7f2 51401#if defined(DUK_USE_ES6_PROXY)
7c673cae
FG
51402 fail_proxy_rejected:
51403 DUK_DDD(DUK_DDDPRINT("result: error, proxy rejects"));
51404 if (throw_flag) {
11fdf7f2 51405 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
7c673cae
FG
51406 }
51407 /* Note: no key on stack */
51408 return 0;
11fdf7f2 51409#endif
7c673cae
FG
51410
51411 fail_base_primitive:
51412 DUK_DDD(DUK_DDDPRINT("result: error, base primitive"));
51413 if (throw_flag) {
11fdf7f2
TL
51414#if defined(DUK_USE_PARANOID_ERRORS)
51415 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
51416#else
51417 DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot write property %s of %s",
51418 duk_push_string_tval_readable(ctx, tv_key), duk_push_string_tval_readable(ctx, tv_obj));
51419#endif
7c673cae
FG
51420 }
51421 duk_pop(ctx); /* remove key */
51422 return 0;
51423
51424 fail_not_extensible:
51425 DUK_DDD(DUK_DDDPRINT("result: error, not extensible"));
51426 if (throw_flag) {
11fdf7f2 51427 DUK_ERROR_TYPE(thr, DUK_STR_NOT_EXTENSIBLE);
7c673cae
FG
51428 }
51429 duk_pop(ctx); /* remove key */
51430 return 0;
51431
51432 fail_not_writable:
51433 DUK_DDD(DUK_DDDPRINT("result: error, not writable"));
51434 if (throw_flag) {
11fdf7f2 51435 DUK_ERROR_TYPE(thr, DUK_STR_NOT_WRITABLE);
7c673cae
FG
51436 }
51437 duk_pop(ctx); /* remove key */
51438 return 0;
51439
11fdf7f2
TL
51440#if defined(DUK_USE_ROM_OBJECTS)
51441 fail_not_writable_no_pop:
51442 DUK_DDD(DUK_DDDPRINT("result: error, not writable"));
51443 if (throw_flag) {
51444 DUK_ERROR_TYPE(thr, DUK_STR_NOT_WRITABLE);
51445 }
51446 return 0;
51447#endif
51448
7c673cae
FG
51449 fail_array_length_partial:
51450 DUK_DDD(DUK_DDDPRINT("result: error, array length write only partially successful"));
51451 if (throw_flag) {
11fdf7f2 51452 DUK_ERROR_TYPE(thr, DUK_STR_ARRAY_LENGTH_WRITE_FAILED);
7c673cae
FG
51453 }
51454 duk_pop(ctx); /* remove key */
51455 return 0;
51456
51457 fail_no_setter:
51458 DUK_DDD(DUK_DDDPRINT("result: error, accessor property without setter"));
51459 if (throw_flag) {
11fdf7f2 51460 DUK_ERROR_TYPE(thr, DUK_STR_SETTER_UNDEFINED);
7c673cae
FG
51461 }
51462 duk_pop(ctx); /* remove key */
51463 return 0;
51464
51465 fail_internal:
51466 DUK_DDD(DUK_DDDPRINT("result: error, internal"));
51467 if (throw_flag) {
11fdf7f2 51468 DUK_ERROR_INTERNAL_DEFMSG(thr);
7c673cae
FG
51469 }
51470 duk_pop(ctx); /* remove key */
51471 return 0;
51472}
51473
51474/*
51475 * Ecmascript compliant [[Delete]](P, Throw).
51476 */
51477
51478DUK_INTERNAL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags) {
51479 duk_propdesc desc;
51480 duk_tval *tv;
7c673cae
FG
51481 duk_uint32_t arr_idx;
51482 duk_bool_t throw_flag;
51483 duk_bool_t force_flag;
51484
51485 throw_flag = (flags & DUK_DELPROP_FLAG_THROW);
51486 force_flag = (flags & DUK_DELPROP_FLAG_FORCE);
51487
51488 DUK_DDD(DUK_DDDPRINT("delprop_raw: thr=%p, obj=%p, key=%p, throw=%ld, force=%ld (obj -> %!O, key -> %!O)",
51489 (void *) thr, (void *) obj, (void *) key, (long) throw_flag, (long) force_flag,
51490 (duk_heaphdr *) obj, (duk_heaphdr *) key));
51491
51492 DUK_ASSERT(thr != NULL);
51493 DUK_ASSERT(thr->heap != NULL);
51494 DUK_ASSERT(obj != NULL);
51495 DUK_ASSERT(key != NULL);
51496
51497 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
51498
51499 arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key);
51500
51501 /* 0 = don't push current value */
11fdf7f2 51502 if (!duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */
7c673cae
FG
51503 DUK_DDD(DUK_DDDPRINT("property not found, succeed always"));
51504 goto success;
51505 }
51506
11fdf7f2
TL
51507#if defined(DUK_USE_ROM_OBJECTS)
51508 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
51509 DUK_DD(DUK_DDPRINT("attempt to delprop on read-only target object"));
51510 goto fail_not_configurable;
51511 }
51512#endif
51513
7c673cae
FG
51514 if ((desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) == 0 && !force_flag) {
51515 goto fail_not_configurable;
51516 }
51517 if (desc.a_idx < 0 && desc.e_idx < 0) {
51518 /* Currently there are no deletable virtual properties, but
51519 * with force_flag we might attempt to delete one.
51520 */
51521 goto fail_virtual;
51522 }
51523
51524 if (desc.a_idx >= 0) {
51525 DUK_ASSERT(desc.e_idx < 0);
51526
51527 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, desc.a_idx);
11fdf7f2 51528 DUK_TVAL_SET_UNUSED_UPDREF(thr, tv); /* side effects */
7c673cae
FG
51529 goto success;
51530 } else {
11fdf7f2
TL
51531 duk_hobject *h_get = NULL;
51532 duk_hobject *h_set = NULL;
51533 duk_tval tv_tmp;
51534
7c673cae
FG
51535 DUK_ASSERT(desc.a_idx < 0);
51536
11fdf7f2
TL
51537 /* Set property slot to an empty state. Careful not to invoke
51538 * any side effects while using desc.e_idx so that it doesn't
51539 * get invalidated by a finalizer mutating our object.
51540 */
51541
7c673cae
FG
51542 /* remove hash entry (no decref) */
51543#if defined(DUK_USE_HOBJECT_HASH_PART)
51544 if (desc.h_idx >= 0) {
51545 duk_uint32_t *h_base = DUK_HOBJECT_H_GET_BASE(thr->heap, obj);
51546
51547 DUK_DDD(DUK_DDDPRINT("removing hash entry at h_idx %ld", (long) desc.h_idx));
51548 DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(obj) > 0);
51549 DUK_ASSERT((duk_uint32_t) desc.h_idx < DUK_HOBJECT_GET_HSIZE(obj));
51550 h_base[desc.h_idx] = DUK__HASH_DELETED;
51551 } else {
51552 DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(obj) == 0);
51553 }
51554#else
51555 DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(obj) == 0);
51556#endif
51557
51558 /* remove value */
51559 DUK_DDD(DUK_DDDPRINT("before removing value, e_idx %ld, key %p, key at slot %p",
51560 (long) desc.e_idx, (void *) key, (void *) DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx)));
51561 DUK_DDD(DUK_DDDPRINT("removing value at e_idx %ld", (long) desc.e_idx));
11fdf7f2
TL
51562 DUK_MEMSET((void *) &tv_tmp, 0, sizeof(tv_tmp));
51563 DUK_TVAL_SET_UNDEFINED(&tv_tmp);
7c673cae 51564 if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, desc.e_idx)) {
11fdf7f2
TL
51565 h_get = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, desc.e_idx);
51566 h_set = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, desc.e_idx);
7c673cae 51567 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, desc.e_idx, NULL);
7c673cae 51568 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, desc.e_idx, NULL);
7c673cae
FG
51569 } else {
51570 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, desc.e_idx);
51571 DUK_TVAL_SET_TVAL(&tv_tmp, tv);
11fdf7f2 51572 DUK_TVAL_SET_UNDEFINED(tv);
7c673cae 51573 }
11fdf7f2
TL
51574#if 0
51575 /* Not strictly necessary because if key == NULL, flag MUST be ignored. */
7c673cae 51576 DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, desc.e_idx, 0);
11fdf7f2 51577#endif
7c673cae
FG
51578
51579 /* remove key */
51580 DUK_DDD(DUK_DDDPRINT("before removing key, e_idx %ld, key %p, key at slot %p",
51581 (long) desc.e_idx, (void *) key, (void *) DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx)));
51582 DUK_DDD(DUK_DDDPRINT("removing key at e_idx %ld", (long) desc.e_idx));
51583 DUK_ASSERT(key == DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx));
51584 DUK_HOBJECT_E_SET_KEY(thr->heap, obj, desc.e_idx, NULL);
11fdf7f2
TL
51585
51586 /* Do decrefs only with safe pointers to avoid side effects
51587 * disturbing e_idx.
51588 */
51589 DUK_TVAL_DECREF(thr, &tv_tmp);
51590 DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_get);
51591 DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_set);
7c673cae
FG
51592 DUK_HSTRING_DECREF(thr, key);
51593 goto success;
51594 }
51595
51596 DUK_UNREACHABLE();
51597
51598 success:
51599 /*
51600 * Argument exotic [[Delete]] behavior (E5 Section 10.6) is
51601 * a post-check, keeping arguments internal 'map' in sync with
51602 * any successful deletes (note that property does not need to
51603 * exist for delete to 'succeed').
51604 *
51605 * Delete key from 'map'. Since 'map' only contains array index
51606 * keys, we can use arr_idx for a fast skip.
51607 */
51608
51609 DUK_DDD(DUK_DDDPRINT("delete successful, check for arguments exotic behavior"));
51610
51611 if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj)) {
51612 /* Note: only numbered indices are relevant, so arr_idx fast reject
51613 * is good (this is valid unless there are more than 4**32-1 arguments).
51614 */
51615
51616 DUK_DDD(DUK_DDDPRINT("delete successful, arguments exotic behavior needed"));
51617
51618 /* Note: we can reuse 'desc' here */
51619 (void) duk__check_arguments_map_for_delete(thr, obj, key, &desc);
51620 }
51621
51622 DUK_DDD(DUK_DDDPRINT("delete successful"));
51623 return 1;
51624
51625 fail_virtual:
51626 DUK_DDD(DUK_DDDPRINT("delete failed: property found, force flag, but virtual"));
51627
51628 if (throw_flag) {
11fdf7f2 51629 DUK_ERROR_TYPE(thr, DUK_STR_PROPERTY_IS_VIRTUAL);
7c673cae
FG
51630 }
51631 return 0;
51632
51633 fail_not_configurable:
51634 DUK_DDD(DUK_DDDPRINT("delete failed: property found, not configurable"));
51635
51636 if (throw_flag) {
11fdf7f2 51637 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
7c673cae
FG
51638 }
51639 return 0;
51640}
51641
51642/*
51643 * DELPROP: Ecmascript property deletion.
51644 */
51645
51646DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_bool_t throw_flag) {
51647 duk_context *ctx = (duk_context *) thr;
51648 duk_hstring *key = NULL;
51649#if defined(DUK_USE_ES6_PROXY)
51650 duk_propdesc desc;
51651#endif
51652 duk_int_t entry_top;
51653 duk_uint32_t arr_idx = DUK__NO_ARRAY_INDEX;
51654 duk_bool_t rc;
51655
51656 DUK_DDD(DUK_DDDPRINT("delprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)",
51657 (void *) thr, (void *) tv_obj, (void *) tv_key,
51658 (duk_tval *) tv_obj, (duk_tval *) tv_key));
51659
51660 DUK_ASSERT(ctx != NULL);
51661 DUK_ASSERT(thr != NULL);
51662 DUK_ASSERT(thr->heap != NULL);
51663 DUK_ASSERT(tv_obj != NULL);
51664 DUK_ASSERT(tv_key != NULL);
51665
51666 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
51667
51668 /* Storing the entry top is cheaper here to ensure stack is correct at exit,
51669 * as there are several paths out.
51670 */
51671 entry_top = duk_get_top(ctx);
51672
51673 if (DUK_TVAL_IS_UNDEFINED(tv_obj) ||
51674 DUK_TVAL_IS_NULL(tv_obj)) {
51675 DUK_DDD(DUK_DDDPRINT("base object is undefined or null -> reject"));
51676 goto fail_invalid_base_uncond;
51677 }
51678
51679 duk_push_tval(ctx, tv_obj);
51680 duk_push_tval(ctx, tv_key);
51681
11fdf7f2 51682 tv_obj = DUK_GET_TVAL_NEGIDX(ctx, -2);
7c673cae
FG
51683 if (DUK_TVAL_IS_OBJECT(tv_obj)) {
51684 duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv_obj);
51685 DUK_ASSERT(obj != NULL);
51686
51687#if defined(DUK_USE_ES6_PROXY)
51688 if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
51689 duk_hobject *h_target;
51690 duk_bool_t tmp_bool;
51691
51692 /* Note: proxy handling must happen before key is string coerced. */
51693
51694 if (duk__proxy_check_prop(thr, obj, DUK_STRIDX_DELETE_PROPERTY, tv_key, &h_target)) {
11fdf7f2 51695 /* -> [ ... obj key trap handler ] */
7c673cae
FG
51696 DUK_DDD(DUK_DDDPRINT("-> proxy object 'deleteProperty' for key %!T", (duk_tval *) tv_key));
51697 duk_push_hobject(ctx, h_target); /* target */
11fdf7f2 51698 duk_dup(ctx, -4); /* P */
7c673cae
FG
51699 duk_call_method(ctx, 2 /*nargs*/);
51700 tmp_bool = duk_to_boolean(ctx, -1);
51701 duk_pop(ctx);
51702 if (!tmp_bool) {
51703 goto fail_proxy_rejected; /* retval indicates delete failed */
51704 }
51705
51706 /* Target object must be checked for a conflicting
51707 * non-configurable property.
51708 */
11fdf7f2 51709 tv_key = DUK_GET_TVAL_NEGIDX(ctx, -1);
7c673cae
FG
51710 arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
51711 DUK_ASSERT(key != NULL);
51712
11fdf7f2 51713 if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */
7c673cae
FG
51714 int desc_reject;
51715
51716 DUK_DDD(DUK_DDDPRINT("proxy 'deleteProperty': target has matching property %!O, check for "
51717 "conflicting property; desc.flags=0x%08lx, "
51718 "desc.get=%p, desc.set=%p",
51719 (duk_heaphdr *) key, (unsigned long) desc.flags,
51720 (void *) desc.get, (void *) desc.set));
51721
51722 desc_reject = !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE);
51723 if (desc_reject) {
51724 /* unconditional */
11fdf7f2 51725 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
7c673cae
FG
51726 }
51727 }
51728 rc = 1; /* success */
51729 goto done_rc;
51730 }
51731
51732 obj = h_target; /* resume delete to target */
51733 }
51734#endif /* DUK_USE_ES6_PROXY */
51735
51736 duk_to_string(ctx, -1);
51737 key = duk_get_hstring(ctx, -1);
51738 DUK_ASSERT(key != NULL);
51739
51740 rc = duk_hobject_delprop_raw(thr, obj, key, throw_flag ? DUK_DELPROP_FLAG_THROW : 0);
51741 goto done_rc;
51742 } else if (DUK_TVAL_IS_STRING(tv_obj)) {
51743 /* XXX: unnecessary string coercion for array indices,
51744 * intentional to keep small.
51745 */
51746 duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj);
51747 DUK_ASSERT(h != NULL);
51748
51749 duk_to_string(ctx, -1);
51750 key = duk_get_hstring(ctx, -1);
51751 DUK_ASSERT(key != NULL);
51752
51753 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
51754 goto fail_not_configurable;
51755 }
51756
51757 arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key);
51758
51759 if (arr_idx != DUK__NO_ARRAY_INDEX &&
51760 arr_idx < DUK_HSTRING_GET_CHARLEN(h)) {
51761 goto fail_not_configurable;
51762 }
51763 } else if (DUK_TVAL_IS_BUFFER(tv_obj)) {
51764 /* XXX: unnecessary string coercion for array indices,
51765 * intentional to keep small; some overlap with string
51766 * handling.
51767 */
51768 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj);
51769 DUK_ASSERT(h != NULL);
51770
51771 duk_to_string(ctx, -1);
51772 key = duk_get_hstring(ctx, -1);
51773 DUK_ASSERT(key != NULL);
51774
51775 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
51776 goto fail_not_configurable;
51777 }
51778
51779 arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key);
51780
51781 if (arr_idx != DUK__NO_ARRAY_INDEX &&
51782 arr_idx < DUK_HBUFFER_GET_SIZE(h)) {
51783 goto fail_not_configurable;
51784 }
51785 } else if (DUK_TVAL_IS_LIGHTFUNC(tv_obj)) {
51786 /* Lightfunc virtual properties are non-configurable, so
51787 * reject if match any of them.
51788 */
51789
51790 duk_to_string(ctx, -1);
51791 key = duk_get_hstring(ctx, -1);
51792 DUK_ASSERT(key != NULL);
51793
51794 if (duk__key_is_lightfunc_ownprop(thr, key)) {
51795 goto fail_not_configurable;
51796 }
51797 }
51798
51799 /* non-object base, no offending virtual property */
51800 rc = 1;
51801 goto done_rc;
51802
51803 done_rc:
51804 duk_set_top(ctx, entry_top);
51805 return rc;
51806
51807 fail_invalid_base_uncond:
51808 /* Note: unconditional throw */
51809 DUK_ASSERT(duk_get_top(ctx) == entry_top);
11fdf7f2
TL
51810#if defined(DUK_USE_PARANOID_ERRORS)
51811 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
51812#else
51813 DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot delete property %s of %s",
51814 duk_push_string_tval_readable(ctx, tv_key), duk_push_string_tval_readable(ctx, tv_obj));
51815#endif
7c673cae
FG
51816 return 0;
51817
11fdf7f2 51818#if defined(DUK_USE_ES6_PROXY)
7c673cae
FG
51819 fail_proxy_rejected:
51820 if (throw_flag) {
11fdf7f2 51821 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
7c673cae
FG
51822 }
51823 duk_set_top(ctx, entry_top);
51824 return 0;
11fdf7f2 51825#endif
7c673cae
FG
51826
51827 fail_not_configurable:
51828 if (throw_flag) {
11fdf7f2 51829 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
7c673cae
FG
51830 }
51831 duk_set_top(ctx, entry_top);
51832 return 0;
51833}
51834
51835/*
51836 * Internal helper to define a property with specific flags, ignoring
51837 * normal semantics such as extensibility, write protection etc.
51838 * Overwrites any existing value and attributes unless caller requests
51839 * that value only be updated if it doesn't already exists.
51840 *
51841 * Does not support:
51842 * - virtual properties (error if write attempted)
51843 * - getter/setter properties (error if write attempted)
51844 * - non-default (!= WEC) attributes for array entries (error if attempted)
51845 * - array abandoning: if array part exists, it is always extended
51846 * - array 'length' updating
51847 *
51848 * Stack: [... in_val] -> []
51849 *
51850 * Used for e.g. built-in initialization and environment record
51851 * operations.
51852 */
51853
51854DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags) {
51855 duk_context *ctx = (duk_context *) thr;
51856 duk_propdesc desc;
51857 duk_uint32_t arr_idx;
51858 duk_int_t e_idx;
7c673cae
FG
51859 duk_tval *tv1 = NULL;
51860 duk_tval *tv2 = NULL;
51861 duk_small_uint_t propflags = flags & DUK_PROPDESC_FLAGS_MASK; /* mask out flags not actually stored */
51862
51863 DUK_DDD(DUK_DDDPRINT("define new property (internal): thr=%p, obj=%!O, key=%!O, flags=0x%02lx, val=%!T",
51864 (void *) thr, (duk_heaphdr *) obj, (duk_heaphdr *) key,
51865 (unsigned long) flags, (duk_tval *) duk_get_tval(ctx, -1)));
51866
51867 DUK_ASSERT(thr != NULL);
51868 DUK_ASSERT(thr->heap != NULL);
51869 DUK_ASSERT(obj != NULL);
51870 DUK_ASSERT(key != NULL);
11fdf7f2 51871 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
7c673cae
FG
51872 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
51873 DUK_ASSERT(duk_is_valid_index(ctx, -1)); /* contains value */
51874
51875 arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
51876
11fdf7f2 51877 if (duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */
7c673cae
FG
51878 if (desc.e_idx >= 0) {
51879 if (flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) {
51880 DUK_DDD(DUK_DDDPRINT("property already exists in the entry part -> skip as requested"));
51881 goto pop_exit;
51882 }
51883 DUK_DDD(DUK_DDDPRINT("property already exists in the entry part -> update value and attributes"));
51884 if (DUK_UNLIKELY(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, desc.e_idx))) {
51885 DUK_D(DUK_DPRINT("existing property is an accessor, not supported"));
51886 goto error_internal;
51887 }
51888
51889 DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, desc.e_idx, propflags);
51890 tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, desc.e_idx);
51891 } else if (desc.a_idx >= 0) {
51892 if (flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) {
51893 DUK_DDD(DUK_DDDPRINT("property already exists in the array part -> skip as requested"));
51894 goto pop_exit;
51895 }
51896 DUK_DDD(DUK_DDDPRINT("property already exists in the array part -> update value (assert attributes)"));
51897 if (propflags != DUK_PROPDESC_FLAGS_WEC) {
51898 DUK_D(DUK_DPRINT("existing property in array part, but propflags not WEC (0x%02lx)",
51899 (unsigned long) propflags));
51900 goto error_internal;
51901 }
51902
51903 tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, desc.a_idx);
51904 } else {
51905 if (flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) {
51906 DUK_DDD(DUK_DDDPRINT("property already exists but is virtual -> skip as requested"));
51907 goto pop_exit;
51908 }
51909 DUK_DDD(DUK_DDDPRINT("property already exists but is virtual -> failure"));
51910 goto error_virtual;
51911 }
51912
51913 goto write_value;
51914 }
51915
51916 if (DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
51917 if (arr_idx != DUK__NO_ARRAY_INDEX) {
51918 DUK_DDD(DUK_DDDPRINT("property does not exist, object has array part -> possibly extend array part and write value (assert attributes)"));
51919 DUK_ASSERT(propflags == DUK_PROPDESC_FLAGS_WEC);
51920
51921 /* always grow the array, no sparse / abandon support here */
51922 if (arr_idx >= DUK_HOBJECT_GET_ASIZE(obj)) {
51923 duk__grow_props_for_array_item(thr, obj, arr_idx);
51924 }
51925
51926 DUK_ASSERT(arr_idx < DUK_HOBJECT_GET_ASIZE(obj));
51927 tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx);
51928 goto write_value;
51929 }
51930 }
51931
51932 DUK_DDD(DUK_DDDPRINT("property does not exist, object belongs in entry part -> allocate new entry and write value and attributes"));
51933 e_idx = duk__alloc_entry_checked(thr, obj, key); /* increases key refcount */
51934 DUK_ASSERT(e_idx >= 0);
51935 DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, e_idx, propflags);
51936 tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx);
51937 /* new entry: previous value is garbage; set to undefined to share write_value */
11fdf7f2 51938 DUK_TVAL_SET_UNDEFINED(tv1);
7c673cae
FG
51939 goto write_value;
51940
51941 write_value:
51942 /* tv1 points to value storage */
51943
51944 tv2 = duk_require_tval(ctx, -1); /* late lookup, avoid side effects */
51945 DUK_DDD(DUK_DDDPRINT("writing/updating value: %!T -> %!T",
51946 (duk_tval *) tv1, (duk_tval *) tv2));
51947
11fdf7f2 51948 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
7c673cae
FG
51949 goto pop_exit;
51950
51951 pop_exit:
51952 duk_pop(ctx); /* remove in_val */
51953 return;
51954
51955 error_internal:
11fdf7f2 51956 DUK_ERROR_INTERNAL_DEFMSG(thr);
7c673cae
FG
51957 return;
51958
51959 error_virtual:
11fdf7f2 51960 DUK_ERROR_TYPE(thr, DUK_STR_REDEFINE_VIRT_PROP);
7c673cae
FG
51961 return;
51962}
51963
51964/*
51965 * Fast path for defining array indexed values without interning the key.
51966 * This is used by e.g. code for Array prototype and traceback creation so
51967 * must avoid interning.
51968 */
51969
51970DUK_INTERNAL void duk_hobject_define_property_internal_arridx(duk_hthread *thr, duk_hobject *obj, duk_uarridx_t arr_idx, duk_small_uint_t flags) {
51971 duk_context *ctx = (duk_context *) thr;
51972 duk_hstring *key;
51973 duk_tval *tv1, *tv2;
7c673cae
FG
51974
51975 DUK_DDD(DUK_DDDPRINT("define new property (internal) arr_idx fast path: thr=%p, obj=%!O, "
51976 "arr_idx=%ld, flags=0x%02lx, val=%!T",
51977 (void *) thr, obj, (long) arr_idx, (unsigned long) flags,
51978 (duk_tval *) duk_get_tval(ctx, -1)));
51979
51980 DUK_ASSERT(thr != NULL);
51981 DUK_ASSERT(thr->heap != NULL);
51982 DUK_ASSERT(obj != NULL);
11fdf7f2 51983 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
7c673cae
FG
51984
51985 if (DUK_HOBJECT_HAS_ARRAY_PART(obj) &&
51986 arr_idx != DUK__NO_ARRAY_INDEX &&
51987 flags == DUK_PROPDESC_FLAGS_WEC) {
51988 DUK_ASSERT((flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) == 0); /* covered by comparison */
51989
51990 DUK_DDD(DUK_DDDPRINT("define property to array part (property may or may not exist yet)"));
51991
51992 /* always grow the array, no sparse / abandon support here */
51993 if (arr_idx >= DUK_HOBJECT_GET_ASIZE(obj)) {
51994 duk__grow_props_for_array_item(thr, obj, arr_idx);
51995 }
51996
51997 DUK_ASSERT(arr_idx < DUK_HOBJECT_GET_ASIZE(obj));
51998 tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx);
51999 tv2 = duk_require_tval(ctx, -1);
52000
11fdf7f2 52001 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
7c673cae
FG
52002
52003 duk_pop(ctx); /* [ ...val ] -> [ ... ] */
52004 return;
52005 }
52006
52007 DUK_DDD(DUK_DDDPRINT("define property fast path didn't work, use slow path"));
52008
52009 duk_push_uint(ctx, (duk_uint_t) arr_idx);
52010 key = duk_to_hstring(ctx, -1);
52011 DUK_ASSERT(key != NULL);
52012 duk_insert(ctx, -2); /* [ ... val key ] -> [ ... key val ] */
52013
52014 duk_hobject_define_property_internal(thr, obj, key, flags);
52015
52016 duk_pop(ctx); /* [ ... key ] -> [ ... ] */
52017}
52018
52019/*
52020 * Internal helper for defining an accessor property, ignoring
52021 * normal semantics such as extensibility, write protection etc.
52022 * Overwrites any existing value and attributes. This is called
52023 * very rarely, so the implementation first sets a value to undefined
52024 * and then changes the entry to an accessor (this is to save code space).
52025 */
52026
52027DUK_INTERNAL void duk_hobject_define_accessor_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_hobject *getter, duk_hobject *setter, duk_small_uint_t propflags) {
52028 duk_context *ctx = (duk_context *) thr;
52029 duk_int_t e_idx;
52030 duk_int_t h_idx;
52031
52032 DUK_DDD(DUK_DDDPRINT("define new accessor (internal): thr=%p, obj=%!O, key=%!O, "
52033 "getter=%!O, setter=%!O, flags=0x%02lx",
52034 (void *) thr, (duk_heaphdr *) obj, (duk_heaphdr *) key,
52035 (duk_heaphdr *) getter, (duk_heaphdr *) setter,
52036 (unsigned long) propflags));
52037
52038 DUK_ASSERT(thr != NULL);
52039 DUK_ASSERT(thr->heap != NULL);
52040 DUK_ASSERT(obj != NULL);
52041 DUK_ASSERT(key != NULL);
52042 DUK_ASSERT((propflags & ~DUK_PROPDESC_FLAGS_MASK) == 0);
52043 /* setter and/or getter may be NULL */
11fdf7f2 52044 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
7c673cae
FG
52045
52046 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
52047
52048 /* force the property to 'undefined' to create a slot for it */
52049 duk_push_undefined(ctx);
52050 duk_hobject_define_property_internal(thr, obj, key, propflags);
52051 duk_hobject_find_existing_entry(thr->heap, obj, key, &e_idx, &h_idx);
52052 DUK_DDD(DUK_DDDPRINT("accessor slot: e_idx=%ld, h_idx=%ld", (long) e_idx, (long) h_idx));
52053 DUK_ASSERT(e_idx >= 0);
52054 DUK_ASSERT((duk_uint32_t) e_idx < DUK_HOBJECT_GET_ENEXT(obj));
52055
52056 /* no need to decref, as previous value is 'undefined' */
52057 DUK_HOBJECT_E_SLOT_SET_ACCESSOR(thr->heap, obj, e_idx);
52058 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, e_idx, getter);
52059 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, e_idx, setter);
52060 DUK_HOBJECT_INCREF_ALLOWNULL(thr, getter);
52061 DUK_HOBJECT_INCREF_ALLOWNULL(thr, setter);
52062}
52063
52064/*
52065 * Internal helpers for managing object 'length'
52066 */
52067
52068/* XXX: awkward helpers */
52069
52070DUK_INTERNAL void duk_hobject_set_length(duk_hthread *thr, duk_hobject *obj, duk_uint32_t length) {
52071 duk_context *ctx = (duk_context *) thr;
52072 duk_push_hobject(ctx, obj);
52073 duk_push_hstring_stridx(ctx, DUK_STRIDX_LENGTH);
52074 duk_push_u32(ctx, length);
11fdf7f2
TL
52075 (void) duk_hobject_putprop(thr,
52076 DUK_GET_TVAL_NEGIDX(ctx, -3),
52077 DUK_GET_TVAL_NEGIDX(ctx, -2),
52078 DUK_GET_TVAL_NEGIDX(ctx, -1),
52079 0);
7c673cae
FG
52080 duk_pop_n(ctx, 3);
52081}
52082
52083DUK_INTERNAL void duk_hobject_set_length_zero(duk_hthread *thr, duk_hobject *obj) {
52084 duk_hobject_set_length(thr, obj, 0);
52085}
52086
52087DUK_INTERNAL duk_uint32_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj) {
52088 duk_context *ctx = (duk_context *) thr;
52089 duk_double_t val;
52090 duk_push_hobject(ctx, obj);
52091 duk_push_hstring_stridx(ctx, DUK_STRIDX_LENGTH);
11fdf7f2
TL
52092 (void) duk_hobject_getprop(thr,
52093 DUK_GET_TVAL_NEGIDX(ctx, -2),
52094 DUK_GET_TVAL_NEGIDX(ctx, -1));
7c673cae
FG
52095 val = duk_to_number(ctx, -1);
52096 duk_pop_n(ctx, 3);
52097 if (val >= 0.0 && val < DUK_DOUBLE_2TO32) {
52098 return (duk_uint32_t) val;
52099 }
52100 return 0;
52101}
52102
52103/*
52104 * Object.getOwnPropertyDescriptor() (E5 Sections 15.2.3.3, 8.10.4)
52105 *
52106 * This is an actual function call.
52107 */
52108
52109DUK_INTERNAL duk_ret_t duk_hobject_object_get_own_property_descriptor(duk_context *ctx) {
52110 duk_hthread *thr = (duk_hthread *) ctx;
52111 duk_hobject *obj;
52112 duk_hstring *key;
52113 duk_propdesc pd;
52114 duk_bool_t rc;
52115
52116 DUK_ASSERT(ctx != NULL);
52117 DUK_ASSERT(thr != NULL);
52118 DUK_ASSERT(thr->heap != NULL);
52119
52120 obj = duk_require_hobject_or_lfunc_coerce(ctx, 0);
52121 (void) duk_to_string(ctx, 1);
52122 key = duk_require_hstring(ctx, 1);
52123
52124 DUK_ASSERT(obj != NULL);
52125 DUK_ASSERT(key != NULL);
52126
52127 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
52128
11fdf7f2 52129 rc = duk_hobject_get_own_propdesc(thr, obj, key, &pd, DUK_GETDESC_FLAG_PUSH_VALUE);
7c673cae
FG
52130 if (!rc) {
52131 duk_push_undefined(ctx);
52132
52133 /* [obj key undefined] */
52134 return 1;
52135 }
52136
52137 duk_push_object(ctx);
52138
52139 /* [obj key value desc] */
52140
52141 if (DUK_PROPDESC_IS_ACCESSOR(&pd)) {
52142 /* If a setter/getter is missing (undefined), the descriptor must
52143 * still have the property present with the value 'undefined'.
52144 */
52145 if (pd.get) {
52146 duk_push_hobject(ctx, pd.get);
52147 } else {
52148 duk_push_undefined(ctx);
52149 }
52150 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_GET);
52151 if (pd.set) {
52152 duk_push_hobject(ctx, pd.set);
52153 } else {
52154 duk_push_undefined(ctx);
52155 }
52156 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_SET);
52157 } else {
52158 duk_dup(ctx, -2); /* [obj key value desc value] */
52159 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_VALUE);
52160 duk_push_boolean(ctx, DUK_PROPDESC_IS_WRITABLE(&pd));
52161 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_WRITABLE);
52162
52163 /* [obj key value desc] */
52164 }
52165 duk_push_boolean(ctx, DUK_PROPDESC_IS_ENUMERABLE(&pd));
52166 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_ENUMERABLE);
52167 duk_push_boolean(ctx, DUK_PROPDESC_IS_CONFIGURABLE(&pd));
52168 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_CONFIGURABLE);
52169
52170 /* [obj key value desc] */
52171 return 1;
52172}
52173
52174/*
52175 * NormalizePropertyDescriptor() related helper.
52176 *
52177 * Internal helper which validates and normalizes a property descriptor
52178 * represented as an Ecmascript object (e.g. argument to defineProperty()).
52179 * The output of this conversion is a set of defprop_flags and possibly
52180 * some values pushed on the value stack; some subset of: property value,
52181 * getter, setter. Caller must manage stack top carefully because the
52182 * number of values pushed depends on the input property descriptor.
52183 *
52184 * The original descriptor object must not be altered in the process.
52185 */
52186
52187/* XXX: very basic optimization -> duk_get_prop_stridx_top */
52188
52189DUK_INTERNAL
52190void duk_hobject_prepare_property_descriptor(duk_context *ctx,
52191 duk_idx_t idx_in,
52192 duk_uint_t *out_defprop_flags,
52193 duk_idx_t *out_idx_value,
52194 duk_hobject **out_getter,
52195 duk_hobject **out_setter) {
52196 duk_hthread *thr = (duk_hthread *) ctx;
52197 duk_idx_t idx_value = -1;
52198 duk_hobject *getter = NULL;
52199 duk_hobject *setter = NULL;
52200 duk_bool_t is_data_desc = 0;
52201 duk_bool_t is_acc_desc = 0;
52202 duk_uint_t defprop_flags = 0;
52203
52204 DUK_ASSERT(ctx != NULL);
52205 DUK_ASSERT(out_defprop_flags != NULL);
52206 DUK_ASSERT(out_idx_value != NULL);
52207 DUK_ASSERT(out_getter != NULL);
52208 DUK_ASSERT(out_setter != NULL);
52209
52210 /* Must be an object, otherwise TypeError (E5.1 Section 8.10.5, step 1). */
52211 idx_in = duk_require_normalize_index(ctx, idx_in);
52212 (void) duk_require_hobject(ctx, idx_in);
52213
52214 /* The coercion order must match the ToPropertyDescriptor() algorithm
52215 * so that side effects in coercion happen in the correct order.
52216 * (This order also happens to be compatible with duk_def_prop(),
52217 * although it doesn't matter in practice.)
52218 */
52219
52220 if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_VALUE)) {
52221 is_data_desc = 1;
52222 defprop_flags |= DUK_DEFPROP_HAVE_VALUE;
52223 idx_value = duk_get_top_index(ctx);
52224 /* Leave 'value' on stack */
52225 } else {
52226 duk_pop(ctx);
52227 }
52228
52229 if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_WRITABLE)) {
52230 is_data_desc = 1;
52231 if (duk_to_boolean(ctx, -1)) {
52232 defprop_flags |= DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE;
52233 } else {
52234 defprop_flags |= DUK_DEFPROP_HAVE_WRITABLE;
52235 }
52236 }
52237 duk_pop(ctx);
52238
52239 if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_GET)) {
52240 duk_tval *tv = duk_require_tval(ctx, -1);
52241 duk_hobject *h_get;
52242
52243 if (DUK_TVAL_IS_UNDEFINED(tv)) {
52244 /* undefined is accepted */
52245 DUK_ASSERT(getter == NULL);
52246 } else {
52247 /* NOTE: lightfuncs are coerced to full functions because
52248 * lightfuncs don't fit into a property value slot. This
52249 * has some side effects, see test-dev-lightfunc-accessor.js.
52250 */
52251 h_get = duk_get_hobject_or_lfunc_coerce(ctx, -1);
52252 if (h_get == NULL || !DUK_HOBJECT_IS_CALLABLE(h_get)) {
52253 goto type_error;
52254 }
52255 getter = h_get;
52256 }
52257 is_acc_desc = 1;
52258 defprop_flags |= DUK_DEFPROP_HAVE_GETTER;
52259 /* Leave 'getter' on stack */
52260 } else {
52261 duk_pop(ctx);
52262 }
52263
52264 if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_SET)) {
52265 duk_tval *tv = duk_require_tval(ctx, -1);
52266 duk_hobject *h_set;
52267
7c673cae
FG
52268 if (DUK_TVAL_IS_UNDEFINED(tv)) {
52269 /* undefined is accepted */
52270 DUK_ASSERT(setter == NULL);
52271 } else {
52272 /* NOTE: lightfuncs are coerced to full functions because
52273 * lightfuncs don't fit into a property value slot. This
52274 * has some side effects, see test-dev-lightfunc-accessor.js.
52275 */
52276 h_set = duk_get_hobject_or_lfunc_coerce(ctx, -1);
52277 if (h_set == NULL || !DUK_HOBJECT_IS_CALLABLE(h_set)) {
52278 goto type_error;
52279 }
52280 setter = h_set;
52281 }
52282 is_acc_desc = 1;
52283 defprop_flags |= DUK_DEFPROP_HAVE_SETTER;
52284 /* Leave 'setter' on stack */
52285 } else {
52286 duk_pop(ctx);
52287 }
52288
52289 if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_ENUMERABLE)) {
52290 if (duk_to_boolean(ctx, -1)) {
52291 defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE;
52292 } else {
52293 defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE;
52294 }
52295 }
52296 duk_pop(ctx);
52297
52298 if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_CONFIGURABLE)) {
52299 if (duk_to_boolean(ctx, -1)) {
52300 defprop_flags |= DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE;
52301 } else {
52302 defprop_flags |= DUK_DEFPROP_HAVE_CONFIGURABLE;
52303 }
52304 }
52305 duk_pop(ctx);
52306
52307 if (is_data_desc && is_acc_desc) {
52308 goto type_error;
52309 }
52310
52311 *out_defprop_flags = defprop_flags;
52312 *out_idx_value = idx_value;
52313 *out_getter = getter;
52314 *out_setter = setter;
52315
52316 /* [ ... value? getter? setter? ] */
52317 return;
52318
52319 type_error:
11fdf7f2 52320 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_DESCRIPTOR);
7c673cae
FG
52321}
52322
52323/*
52324 * Object.defineProperty() related helper (E5 Section 15.2.3.6)
52325 *
52326 * Inlines all [[DefineOwnProperty]] exotic behaviors.
52327 *
52328 * Note: Ecmascript compliant [[DefineOwnProperty]](P, Desc, Throw) is not
52329 * implemented directly, but Object.defineProperty() serves its purpose.
52330 * We don't need the [[DefineOwnProperty]] internally and we don't have a
52331 * property descriptor with 'missing values' so it's easier to avoid it
52332 * entirely.
52333 *
52334 * Note: this is only called for actual objects, not primitive values.
52335 * This must support virtual properties for full objects (e.g. Strings)
52336 * but not for plain values (e.g. strings). Lightfuncs, even though
52337 * primitive in a sense, are treated like objects and accepted as target
52338 * values.
52339 */
52340
52341/* XXX: this is a major target for size optimization */
52342DUK_INTERNAL
52343void duk_hobject_define_property_helper(duk_context *ctx,
52344 duk_uint_t defprop_flags,
52345 duk_hobject *obj,
52346 duk_hstring *key,
52347 duk_idx_t idx_value,
52348 duk_hobject *get,
52349 duk_hobject *set) {
52350 duk_hthread *thr = (duk_hthread *) ctx;
52351 duk_uint32_t arr_idx;
52352 duk_tval tv;
52353 duk_bool_t has_enumerable;
52354 duk_bool_t has_configurable;
52355 duk_bool_t has_writable;
52356 duk_bool_t has_value;
52357 duk_bool_t has_get;
52358 duk_bool_t has_set;
52359 duk_bool_t is_enumerable;
52360 duk_bool_t is_configurable;
52361 duk_bool_t is_writable;
52362 duk_bool_t throw_flag;
52363 duk_bool_t force_flag;
52364 duk_small_uint_t new_flags;
52365 duk_propdesc curr;
52366 duk_uint32_t arridx_new_array_length; /* != 0 => post-update for array 'length' (used when key is an array index) */
52367 duk_uint32_t arrlen_old_len;
52368 duk_uint32_t arrlen_new_len;
52369 duk_bool_t pending_write_protect;
52370
52371 DUK_ASSERT(thr != NULL);
52372 DUK_ASSERT(thr->heap != NULL);
52373 DUK_ASSERT(ctx != NULL);
52374 DUK_ASSERT(obj != NULL);
52375 DUK_ASSERT(key != NULL);
52376 /* idx_value may be < 0 (no value), set and get may be NULL */
52377
52378 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
52379
52380 /* All the flags fit in 16 bits, so will fit into duk_bool_t. */
52381
52382 has_writable = (defprop_flags & DUK_DEFPROP_HAVE_WRITABLE);
52383 has_enumerable = (defprop_flags & DUK_DEFPROP_HAVE_ENUMERABLE);
52384 has_configurable = (defprop_flags & DUK_DEFPROP_HAVE_CONFIGURABLE);
52385 has_value = (defprop_flags & DUK_DEFPROP_HAVE_VALUE);
52386 has_get = (defprop_flags & DUK_DEFPROP_HAVE_GETTER);
52387 has_set = (defprop_flags & DUK_DEFPROP_HAVE_SETTER);
52388 is_writable = (defprop_flags & DUK_DEFPROP_WRITABLE);
52389 is_enumerable = (defprop_flags & DUK_DEFPROP_ENUMERABLE);
52390 is_configurable = (defprop_flags & DUK_DEFPROP_CONFIGURABLE);
52391 throw_flag = 1; /* Object.defineProperty() calls [[DefineOwnProperty]] with Throw=true */
52392 force_flag = (defprop_flags & DUK_DEFPROP_FORCE);
52393
52394 arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
52395
52396 arridx_new_array_length = 0;
52397 pending_write_protect = 0;
52398 arrlen_old_len = 0;
52399 arrlen_new_len = 0;
52400
52401 DUK_DDD(DUK_DDDPRINT("has_enumerable=%ld is_enumerable=%ld "
52402 "has_configurable=%ld is_configurable=%ld "
52403 "has_writable=%ld is_writable=%ld "
52404 "has_value=%ld value=%!T "
52405 "has_get=%ld get=%p=%!O "
52406 "has_set=%ld set=%p=%!O "
52407 "arr_idx=%ld",
52408 (long) has_enumerable, (long) is_enumerable,
52409 (long) has_configurable, (long) is_configurable,
52410 (long) has_writable, (long) is_writable,
52411 (long) has_value, (duk_tval *) (idx_value >= 0 ? duk_get_tval(ctx, idx_value) : NULL),
52412 (long) has_get, (void *) get, (duk_heaphdr *) get,
52413 (long) has_set, (void *) set, (duk_heaphdr *) set,
52414 (long) arr_idx));
52415
52416 /*
52417 * Array exotic behaviors can be implemented at this point. The local variables
52418 * are essentially a 'value copy' of the input descriptor (Desc), which is modified
52419 * by the Array [[DefineOwnProperty]] (E5 Section 15.4.5.1).
52420 */
52421
52422 if (!DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
52423 goto skip_array_exotic;
52424 }
52425
52426 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
52427 /* E5 Section 15.4.5.1, step 3, steps a - i are implemented here, j - n at the end */
52428 if (!has_value) {
52429 DUK_DDD(DUK_DDDPRINT("exotic array behavior for 'length', but no value in descriptor -> normal behavior"));
52430 goto skip_array_exotic;
52431 }
52432
52433 DUK_DDD(DUK_DDDPRINT("exotic array behavior for 'length', value present in descriptor -> exotic behavior"));
52434
52435 /*
52436 * Get old and new length
52437 */
52438
52439 /* Note: reuse 'curr' as a temp propdesc */
52440 arrlen_old_len = duk__get_old_array_length(thr, obj, &curr);
52441
52442 duk_dup(ctx, idx_value);
52443 arrlen_new_len = duk__to_new_array_length_checked(thr);
52444 duk_push_u32(ctx, arrlen_new_len);
52445 duk_replace(ctx, idx_value); /* step 3.e: replace 'Desc.[[Value]]' */
52446
52447 DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld", (long) arrlen_old_len, (long) arrlen_new_len));
52448
52449 if (arrlen_new_len >= arrlen_old_len) {
52450 /* standard behavior, step 3.f.i */
52451 DUK_DDD(DUK_DDDPRINT("new length is same or higher as previous => standard behavior"));
52452 goto skip_array_exotic;
52453 }
52454 DUK_DDD(DUK_DDDPRINT("new length is smaller than previous => exotic post behavior"));
52455
52456 /* XXX: consolidated algorithm step 15.f -> redundant? */
52457 if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE) && !force_flag) {
52458 /* Note: 'curr' refers to 'length' propdesc */
52459 goto fail_not_writable_array_length;
52460 }
52461
52462 /* steps 3.h and 3.i */
52463 if (has_writable && !is_writable) {
52464 DUK_DDD(DUK_DDDPRINT("desc writable is false, force it back to true, and flag pending write protect"));
52465 is_writable = 1;
52466 pending_write_protect = 1;
52467 }
52468
52469 /* remaining actual steps are carried out if standard DefineOwnProperty succeeds */
52470 } else if (arr_idx != DUK__NO_ARRAY_INDEX) {
52471 /* XXX: any chance of unifying this with the 'length' key handling? */
52472
52473 /* E5 Section 15.4.5.1, step 4 */
52474 duk_uint32_t old_len;
52475
52476 /* Note: use 'curr' as a temp propdesc */
52477 old_len = duk__get_old_array_length(thr, obj, &curr);
52478
52479 if (arr_idx >= old_len) {
52480 DUK_DDD(DUK_DDDPRINT("defineProperty requires array length update "
52481 "(arr_idx=%ld, old_len=%ld)",
52482 (long) arr_idx, (long) old_len));
52483
52484 if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
52485 /* Note: 'curr' refers to 'length' propdesc */
52486 goto fail_not_writable_array_length;
52487 }
52488
52489 /* actual update happens once write has been completed without
52490 * error below.
52491 */
52492 DUK_ASSERT(arr_idx != 0xffffffffUL);
52493 arridx_new_array_length = arr_idx + 1;
52494 } else {
52495 DUK_DDD(DUK_DDDPRINT("defineProperty does not require length update "
52496 "(arr_idx=%ld, old_len=%ld) -> standard behavior",
52497 (long) arr_idx, (long) old_len));
52498 }
52499 }
52500 skip_array_exotic:
52501
52502 /* XXX: There is currently no support for writing buffer object
52503 * indexed elements here. Attempt to do so will succeed and
52504 * write a concrete property into the buffer object. This should
52505 * be fixed at some point but because buffers are a custom feature
52506 * anyway, this is relatively unimportant.
52507 */
52508
52509 /*
52510 * Actual Object.defineProperty() default algorithm.
52511 */
52512
52513 /*
52514 * First check whether property exists; if not, simple case. This covers
52515 * steps 1-4.
52516 */
52517
11fdf7f2 52518 if (!duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE)) {
7c673cae
FG
52519 DUK_DDD(DUK_DDDPRINT("property does not exist"));
52520
52521 if (!DUK_HOBJECT_HAS_EXTENSIBLE(obj) && !force_flag) {
52522 goto fail_not_extensible;
52523 }
52524
52525 /* XXX: share final setting code for value and flags? difficult because
52526 * refcount code is different. Share entry allocation? But can't allocate
52527 * until array index checked.
52528 */
52529
52530 /* steps 4.a and 4.b are tricky */
52531 if (has_set || has_get) {
52532 duk_int_t e_idx;
52533
52534 DUK_DDD(DUK_DDDPRINT("create new accessor property"));
52535
52536 DUK_ASSERT(has_set || set == NULL);
52537 DUK_ASSERT(has_get || get == NULL);
52538 DUK_ASSERT(!has_value);
52539 DUK_ASSERT(!has_writable);
52540
52541 new_flags = DUK_PROPDESC_FLAG_ACCESSOR; /* defaults, E5 Section 8.6.1, Table 7 */
52542 if (has_enumerable && is_enumerable) {
52543 new_flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
52544 }
52545 if (has_configurable && is_configurable) {
52546 new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
52547 }
52548
52549 if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
52550 DUK_DDD(DUK_DDDPRINT("accessor cannot go to array part, abandon array"));
52551 duk__abandon_array_checked(thr, obj);
52552 }
52553
52554 /* write to entry part */
52555 e_idx = duk__alloc_entry_checked(thr, obj, key);
52556 DUK_ASSERT(e_idx >= 0);
52557
52558 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, e_idx, get);
52559 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, e_idx, set);
52560 DUK_HOBJECT_INCREF_ALLOWNULL(thr, get);
52561 DUK_HOBJECT_INCREF_ALLOWNULL(thr, set);
52562
52563 DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, e_idx, new_flags);
52564 goto success_exotics;
52565 } else {
52566 duk_int_t e_idx;
52567 duk_tval *tv2;
52568
52569 DUK_DDD(DUK_DDDPRINT("create new data property"));
52570
52571 DUK_ASSERT(!has_set);
52572 DUK_ASSERT(!has_get);
52573
52574 new_flags = 0; /* defaults, E5 Section 8.6.1, Table 7 */
52575 if (has_writable && is_writable) {
52576 new_flags |= DUK_PROPDESC_FLAG_WRITABLE;
52577 }
52578 if (has_enumerable && is_enumerable) {
52579 new_flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
52580 }
52581 if (has_configurable && is_configurable) {
52582 new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
52583 }
52584 if (has_value) {
52585 duk_tval *tv_tmp = duk_require_tval(ctx, idx_value);
52586 DUK_TVAL_SET_TVAL(&tv, tv_tmp);
52587 } else {
11fdf7f2 52588 DUK_TVAL_SET_UNDEFINED(&tv); /* default value */
7c673cae
FG
52589 }
52590
52591 if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
52592 if (new_flags == DUK_PROPDESC_FLAGS_WEC) {
52593#if 0
52594 DUK_DDD(DUK_DDDPRINT("new data property attributes match array defaults, attempt to write to array part"));
52595 /* may become sparse...*/
52596#endif
52597 /* XXX: handling for array part missing now; this doesn't affect
52598 * compliance but causes array entry writes using defineProperty()
52599 * to always abandon array part.
52600 */
52601 }
52602 DUK_DDD(DUK_DDDPRINT("new data property cannot go to array part, abandon array"));
52603 duk__abandon_array_checked(thr, obj);
52604 /* fall through */
52605 }
52606
52607 /* write to entry part */
52608 e_idx = duk__alloc_entry_checked(thr, obj, key);
52609 DUK_ASSERT(e_idx >= 0);
52610 tv2 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx);
52611 DUK_TVAL_SET_TVAL(tv2, &tv);
52612 DUK_TVAL_INCREF(thr, tv2);
52613
52614 DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, e_idx, new_flags);
52615 goto success_exotics;
52616 }
52617 DUK_UNREACHABLE();
52618 }
52619
52620 /* we currently assume virtual properties are not configurable (as none of them are) */
52621 DUK_ASSERT((curr.e_idx >= 0 || curr.a_idx >= 0) || !(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE));
52622
52623 /* [obj key desc value get set curr_value] */
52624
52625 /*
52626 * Property already exists. Steps 5-6 detect whether any changes need
52627 * to be made.
52628 */
52629
52630 if (has_enumerable) {
52631 if (is_enumerable) {
52632 if (!(curr.flags & DUK_PROPDESC_FLAG_ENUMERABLE)) {
52633 goto need_check;
52634 }
52635 } else {
52636 if (curr.flags & DUK_PROPDESC_FLAG_ENUMERABLE) {
52637 goto need_check;
52638 }
52639 }
52640 }
52641 if (has_configurable) {
52642 if (is_configurable) {
52643 if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE)) {
52644 goto need_check;
52645 }
52646 } else {
52647 if (curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) {
52648 goto need_check;
52649 }
52650 }
52651 }
52652 if (has_value) {
52653 duk_tval *tmp1;
52654 duk_tval *tmp2;
52655
52656 /* attempt to change from accessor to data property */
52657 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
52658 goto need_check;
52659 }
52660
52661 tmp1 = duk_require_tval(ctx, -1); /* curr value */
52662 tmp2 = duk_require_tval(ctx, idx_value); /* new value */
52663 if (!duk_js_samevalue(tmp1, tmp2)) {
52664 goto need_check;
52665 }
52666 }
52667 if (has_writable) {
52668 /* attempt to change from accessor to data property */
52669 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
52670 goto need_check;
52671 }
52672
52673 if (is_writable) {
52674 if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
52675 goto need_check;
52676 }
52677 } else {
52678 if (curr.flags & DUK_PROPDESC_FLAG_WRITABLE) {
52679 goto need_check;
52680 }
52681 }
52682 }
52683 if (has_set) {
52684 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
52685 if (set != curr.set) {
52686 goto need_check;
52687 }
52688 } else {
52689 goto need_check;
52690 }
52691 }
52692 if (has_get) {
52693 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
52694 if (get != curr.get) {
52695 goto need_check;
52696 }
52697 } else {
52698 goto need_check;
52699 }
52700 }
52701
52702 /* property exists, either 'desc' is empty, or all values
52703 * match (SameValue)
52704 */
52705 goto success_no_exotics;
52706
52707 need_check:
52708
52709 /*
52710 * Some change(s) need to be made. Steps 7-11.
52711 */
52712
52713 /* shared checks for all descriptor types */
52714 if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
52715 if (has_configurable && is_configurable) {
52716 goto fail_not_configurable;
52717 }
52718 if (has_enumerable) {
52719 if (curr.flags & DUK_PROPDESC_FLAG_ENUMERABLE) {
52720 if (!is_enumerable) {
52721 goto fail_not_configurable;
52722 }
52723 } else {
52724 if (is_enumerable) {
52725 goto fail_not_configurable;
52726 }
52727 }
52728 }
52729 }
52730
52731 /* Reject attempt to change virtual properties: not part of the
52732 * standard algorithm, applies currently to e.g. virtual index
52733 * properties of buffer objects (which are virtual but writable).
52734 * (Cannot "force" modification of a virtual property.)
52735 */
52736 if (curr.flags & DUK_PROPDESC_FLAG_VIRTUAL) {
52737 goto fail_virtual;
52738 }
52739
11fdf7f2
TL
52740 /* Reject attempt to change a read-only object. */
52741#if defined(DUK_USE_ROM_OBJECTS)
52742 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
52743 DUK_DD(DUK_DDPRINT("attempt to define property on read-only target object"));
52744 goto fail_not_configurable;
52745 }
52746#endif
52747
7c673cae
FG
52748 /* descriptor type specific checks */
52749 if (has_set || has_get) {
52750 /* IsAccessorDescriptor(desc) == true */
52751 DUK_ASSERT(!has_writable);
52752 DUK_ASSERT(!has_value);
52753
52754 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
52755 /* curr and desc are accessors */
52756 if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
52757 if (has_set && set != curr.set) {
52758 goto fail_not_configurable;
52759 }
52760 if (has_get && get != curr.get) {
52761 goto fail_not_configurable;
52762 }
52763 }
52764 } else {
52765 duk_bool_t rc;
7c673cae 52766 duk_tval *tv1;
11fdf7f2 52767 duk_tval tv_tmp;
7c673cae
FG
52768
52769 /* curr is data, desc is accessor */
52770 if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
52771 goto fail_not_configurable;
52772 }
52773
52774 DUK_DDD(DUK_DDDPRINT("convert property to accessor property"));
52775 if (curr.a_idx >= 0) {
52776 DUK_DDD(DUK_DDDPRINT("property to convert is stored in an array entry, abandon array and re-lookup"));
52777 duk__abandon_array_checked(thr, obj);
52778 duk_pop(ctx); /* remove old value */
11fdf7f2 52779 rc = duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE);
7c673cae
FG
52780 DUK_UNREF(rc);
52781 DUK_ASSERT(rc != 0);
52782 DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0);
52783 }
52784
52785 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
52786
11fdf7f2
TL
52787 /* Avoid side effects that might disturb curr.e_idx until
52788 * we're done editing the slot.
52789 */
7c673cae
FG
52790 tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx);
52791 DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
11fdf7f2 52792 DUK_TVAL_SET_UNDEFINED(tv1);
7c673cae
FG
52793
52794 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, NULL);
52795 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, NULL);
52796 DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(thr->heap, obj, curr.e_idx);
52797 DUK_HOBJECT_E_SLOT_SET_ACCESSOR(thr->heap, obj, curr.e_idx);
52798
52799 DUK_DDD(DUK_DDDPRINT("flags after data->accessor conversion: 0x%02lx",
52800 (unsigned long) DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, curr.e_idx)));
52801
11fdf7f2
TL
52802 DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
52803
7c673cae
FG
52804 /* re-lookup to update curr.flags
52805 * XXX: would be faster to update directly
52806 */
52807 duk_pop(ctx); /* remove old value */
11fdf7f2 52808 rc = duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE);
7c673cae
FG
52809 DUK_UNREF(rc);
52810 DUK_ASSERT(rc != 0);
52811 }
52812 } else if (has_value || has_writable) {
52813 /* IsDataDescriptor(desc) == true */
52814 DUK_ASSERT(!has_set);
52815 DUK_ASSERT(!has_get);
52816
52817 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
52818 duk_bool_t rc;
11fdf7f2
TL
52819 duk_hobject *h_get;
52820 duk_hobject *h_set;
7c673cae
FG
52821
52822 /* curr is accessor, desc is data */
52823 if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
52824 goto fail_not_configurable;
52825 }
52826
52827 /* curr is accessor -> cannot be in array part */
52828 DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0);
52829
52830 DUK_DDD(DUK_DDDPRINT("convert property to data property"));
52831
11fdf7f2
TL
52832 /* Avoid side effects that might disturb curr.e_idx until
52833 * we're done editing the slot.
52834 */
7c673cae 52835 DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
11fdf7f2 52836 h_get = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, curr.e_idx);
7c673cae 52837 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, NULL);
11fdf7f2 52838 h_set = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, curr.e_idx);
7c673cae 52839 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, NULL);
7c673cae 52840
11fdf7f2 52841 DUK_TVAL_SET_UNDEFINED(DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx));
7c673cae
FG
52842 DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(thr->heap, obj, curr.e_idx);
52843 DUK_HOBJECT_E_SLOT_CLEAR_ACCESSOR(thr->heap, obj, curr.e_idx);
52844
52845 DUK_DDD(DUK_DDDPRINT("flags after accessor->data conversion: 0x%02lx",
52846 (unsigned long) DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, curr.e_idx)));
52847
11fdf7f2
TL
52848 DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_get); /* side effects */
52849 DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_set); /* side effects */
52850
7c673cae
FG
52851 /* re-lookup to update curr.flags
52852 * XXX: would be faster to update directly
52853 */
52854 duk_pop(ctx); /* remove old value */
11fdf7f2 52855 rc = duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE);
7c673cae
FG
52856 DUK_UNREF(rc);
52857 DUK_ASSERT(rc != 0);
52858 } else {
52859 /* curr and desc are data */
52860 if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
52861 if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE) && has_writable && is_writable) {
52862 goto fail_not_configurable;
52863 }
52864 /* Note: changing from writable to non-writable is OK */
52865 if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE) && has_value) {
52866 duk_tval *tmp1 = duk_require_tval(ctx, -1); /* curr value */
52867 duk_tval *tmp2 = duk_require_tval(ctx, idx_value); /* new value */
52868 if (!duk_js_samevalue(tmp1, tmp2)) {
52869 goto fail_not_configurable;
52870 }
52871 }
52872 }
52873 }
52874 } else {
52875 /* IsGenericDescriptor(desc) == true; this means in practice that 'desc'
52876 * only has [[Enumerable]] or [[Configurable]] flag updates, which are
52877 * allowed at this point.
52878 */
52879
52880 DUK_ASSERT(!has_value && !has_writable && !has_get && !has_set);
52881 }
52882
52883 /*
52884 * Start doing property attributes updates. Steps 12-13.
52885 *
52886 * Start by computing new attribute flags without writing yet.
52887 * Property type conversion is done above if necessary.
52888 */
52889
52890 new_flags = curr.flags;
52891
52892 if (has_enumerable) {
52893 if (is_enumerable) {
52894 new_flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
52895 } else {
52896 new_flags &= ~DUK_PROPDESC_FLAG_ENUMERABLE;
52897 }
52898 }
52899 if (has_configurable) {
52900 if (is_configurable) {
52901 new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
52902 } else {
52903 new_flags &= ~DUK_PROPDESC_FLAG_CONFIGURABLE;
52904 }
52905 }
52906 if (has_writable) {
52907 if (is_writable) {
52908 new_flags |= DUK_PROPDESC_FLAG_WRITABLE;
52909 } else {
52910 new_flags &= ~DUK_PROPDESC_FLAG_WRITABLE;
52911 }
52912 }
52913
52914 /* XXX: write protect after flag? -> any chance of handling it here? */
52915
52916 DUK_DDD(DUK_DDDPRINT("new flags that we want to write: 0x%02lx",
52917 (unsigned long) new_flags));
52918
52919 /*
52920 * Check whether we need to abandon an array part (if it exists)
52921 */
52922
52923 if (curr.a_idx >= 0) {
52924 duk_bool_t rc;
52925
52926 DUK_ASSERT(curr.e_idx < 0);
52927
52928 if (new_flags == DUK_PROPDESC_FLAGS_WEC) {
52929 duk_tval *tv1, *tv2;
7c673cae
FG
52930
52931 DUK_DDD(DUK_DDDPRINT("array index, new property attributes match array defaults, update in-place"));
52932
52933 DUK_ASSERT(curr.flags == DUK_PROPDESC_FLAGS_WEC); /* must have been, since in array part */
52934 DUK_ASSERT(!has_set);
52935 DUK_ASSERT(!has_get);
52936
52937 tv2 = duk_require_tval(ctx, idx_value);
52938 tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, curr.a_idx);
11fdf7f2 52939 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
7c673cae
FG
52940 goto success_exotics;
52941 }
52942
52943 DUK_DDD(DUK_DDDPRINT("array index, new property attributes do not match array defaults, abandon array and re-lookup"));
52944 duk__abandon_array_checked(thr, obj);
52945 duk_pop(ctx); /* remove old value */
11fdf7f2 52946 rc = duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE);
7c673cae
FG
52947 DUK_UNREF(rc);
52948 DUK_ASSERT(rc != 0);
52949 DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0);
52950 }
52951
52952 DUK_DDD(DUK_DDDPRINT("updating existing property in entry part"));
52953
52954 /* array case is handled comprehensively above */
52955 DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0);
52956
52957 DUK_DDD(DUK_DDDPRINT("update existing property attributes"));
52958 DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, curr.e_idx, new_flags);
52959
52960 if (has_set) {
52961 duk_hobject *tmp;
52962
52963 DUK_DDD(DUK_DDDPRINT("update existing property setter"));
52964 DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
52965
52966 tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, curr.e_idx);
52967 DUK_UNREF(tmp);
52968 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, set);
52969 DUK_HOBJECT_INCREF_ALLOWNULL(thr, set);
11fdf7f2 52970 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); /* side effects */
7c673cae
FG
52971 }
52972 if (has_get) {
52973 duk_hobject *tmp;
52974
52975 DUK_DDD(DUK_DDDPRINT("update existing property getter"));
52976 DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
52977
52978 tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, curr.e_idx);
52979 DUK_UNREF(tmp);
52980 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, get);
52981 DUK_HOBJECT_INCREF_ALLOWNULL(thr, get);
11fdf7f2 52982 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); /* side effects */
7c673cae
FG
52983 }
52984 if (has_value) {
52985 duk_tval *tv1, *tv2;
7c673cae
FG
52986
52987 DUK_DDD(DUK_DDDPRINT("update existing property value"));
52988 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
52989
52990 tv2 = duk_require_tval(ctx, idx_value);
52991 tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx);
11fdf7f2 52992 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
7c673cae
FG
52993 }
52994
52995 /*
52996 * Standard algorithm succeeded without errors, check for exotic post-behaviors.
52997 *
52998 * Arguments exotic behavior in E5 Section 10.6 occurs after the standard
52999 * [[DefineOwnProperty]] has completed successfully.
53000 *
53001 * Array exotic behavior in E5 Section 15.4.5.1 is implemented partly
53002 * prior to the default [[DefineOwnProperty]], but:
53003 * - for an array index key (e.g. "10") the final 'length' update occurs here
53004 * - for 'length' key the element deletion and 'length' update occurs here
53005 */
53006
53007 success_exotics:
53008
53009 /* [obj key desc value get set curr_value] */
53010
53011 if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
53012 if (arridx_new_array_length > 0) {
53013 duk_tval *tmp;
53014 duk_bool_t rc;
53015
53016 /*
53017 * Note: zero works as a "no update" marker because the new length
53018 * can never be zero after a new property is written.
53019 */
53020
53021 /* E5 Section 15.4.5.1, steps 4.e.i - 4.e.ii */
53022
53023 DUK_DDD(DUK_DDDPRINT("defineProperty successful, pending array length update to: %ld",
53024 (long) arridx_new_array_length));
53025
53026 /* Note: reuse 'curr' */
11fdf7f2 53027 rc = duk__get_own_propdesc_raw(thr, obj, DUK_HTHREAD_STRING_LENGTH(thr), DUK__NO_ARRAY_INDEX, &curr, 0 /*flags*/); /* don't push value */
7c673cae
FG
53028 DUK_UNREF(rc);
53029 DUK_ASSERT(rc != 0);
53030 DUK_ASSERT(curr.e_idx >= 0);
53031
53032 tmp = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx);
53033 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tmp));
53034 /* no need for decref/incref because value is a number */
7c673cae 53035 DUK_TVAL_SET_FASTINT_U32(tmp, arridx_new_array_length);
7c673cae
FG
53036 }
53037 if (key == DUK_HTHREAD_STRING_LENGTH(thr) && arrlen_new_len < arrlen_old_len) {
53038 /*
53039 * E5 Section 15.4.5.1, steps 3.k - 3.n. The order at the end combines
53040 * the error case 3.l.iii and the success case 3.m-3.n.
53041 *
53042 * Note: 'length' is always in entries part, so no array abandon issues for
53043 * 'writable' update.
53044 */
53045
53046 /* XXX: investigate whether write protect can be handled above, if we
53047 * just update length here while ignoring its protected status
53048 */
53049
53050 duk_tval *tmp;
53051 duk_uint32_t result_len;
53052 duk_bool_t rc;
53053
53054 DUK_DDD(DUK_DDDPRINT("defineProperty successful, key is 'length', exotic array behavior, "
53055 "doing array element deletion and length update"));
53056
53057 rc = duk__handle_put_array_length_smaller(thr, obj, arrlen_old_len, arrlen_new_len, force_flag, &result_len);
53058
53059 /* update length (curr points to length, and we assume it's still valid) */
53060 DUK_ASSERT(result_len >= arrlen_new_len && result_len <= arrlen_old_len);
53061
53062 DUK_ASSERT(curr.e_idx >= 0);
53063 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
53064 tmp = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx);
53065 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tmp));
53066 /* no decref needed for a number */
7c673cae 53067 DUK_TVAL_SET_FASTINT_U32(tmp, result_len);
7c673cae
FG
53068 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tmp));
53069
53070 if (pending_write_protect) {
53071 DUK_DDD(DUK_DDDPRINT("setting array length non-writable (pending writability update)"));
53072 DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(thr->heap, obj, curr.e_idx);
53073 }
53074
53075 /*
53076 * XXX: shrink array allocation or entries compaction here?
53077 */
53078
53079 if (!rc) {
53080 goto fail_array_length_partial;
53081 }
53082 }
53083 } else if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj)) {
53084 duk_hobject *map;
53085 duk_hobject *varenv;
53086
53087 DUK_ASSERT(arridx_new_array_length == 0);
53088 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)); /* traits are separate; in particular, arguments not an array */
53089
53090 map = NULL;
53091 varenv = NULL;
53092 if (!duk__lookup_arguments_map(thr, obj, key, &curr, &map, &varenv)) {
53093 goto success_no_exotics;
53094 }
53095 DUK_ASSERT(map != NULL);
53096 DUK_ASSERT(varenv != NULL);
53097
53098 /* [obj key desc value get set curr_value varname] */
53099
53100 if (has_set || has_get) {
53101 /* = IsAccessorDescriptor(Desc) */
53102 DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map' "
53103 "changed to an accessor, delete arguments binding"));
53104
53105 (void) duk_hobject_delprop_raw(thr, map, key, 0); /* ignore result */
53106 } else {
53107 /* Note: this order matters (final value before deleting map entry must be done) */
53108 DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', "
53109 "check for value update / binding deletion"));
53110
53111 if (has_value) {
53112 duk_hstring *varname;
53113
53114 DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', "
53115 "update bound value (variable/argument)"));
53116
53117 varname = duk_require_hstring(ctx, -1);
53118 DUK_ASSERT(varname != NULL);
53119
53120 DUK_DDD(DUK_DDDPRINT("arguments object automatic putvar for a bound variable; "
53121 "key=%!O, varname=%!O, value=%!T",
53122 (duk_heaphdr *) key,
53123 (duk_heaphdr *) varname,
53124 (duk_tval *) duk_require_tval(ctx, idx_value)));
53125
53126 /* strict flag for putvar comes from our caller (currently: fixed) */
53127 duk_js_putvar_envrec(thr, varenv, varname, duk_require_tval(ctx, idx_value), throw_flag);
53128 }
53129 if (has_writable && !is_writable) {
53130 DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', "
53131 "changed to non-writable, delete arguments binding"));
53132
53133 (void) duk_hobject_delprop_raw(thr, map, key, 0); /* ignore result */
53134 }
53135 }
53136
53137 /* 'varname' is in stack in this else branch, leaving an unbalanced stack below,
53138 * but this doesn't matter now.
53139 */
53140 }
53141
53142 success_no_exotics:
53143 return;
53144
53145 fail_virtual:
11fdf7f2 53146 DUK_ERROR_TYPE(thr, DUK_STR_PROPERTY_IS_VIRTUAL);
7c673cae
FG
53147 return;
53148
53149 fail_not_writable_array_length:
11fdf7f2 53150 DUK_ERROR_TYPE(thr, DUK_STR_ARRAY_LENGTH_NOT_WRITABLE);
7c673cae
FG
53151 return;
53152
53153 fail_not_extensible:
11fdf7f2 53154 DUK_ERROR_TYPE(thr, DUK_STR_NOT_EXTENSIBLE);
7c673cae
FG
53155 return;
53156
53157 fail_not_configurable:
11fdf7f2 53158 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
7c673cae
FG
53159 return;
53160
53161 fail_array_length_partial:
11fdf7f2 53162 DUK_ERROR_TYPE(thr, DUK_STR_ARRAY_LENGTH_WRITE_FAILED);
7c673cae
FG
53163 return;
53164}
53165
53166/*
53167 * Object.prototype.hasOwnProperty() and Object.prototype.propertyIsEnumerable().
53168 */
53169
53170DUK_INTERNAL duk_bool_t duk_hobject_object_ownprop_helper(duk_context *ctx, duk_small_uint_t required_desc_flags) {
53171 duk_hthread *thr = (duk_hthread *) ctx;
53172 duk_hstring *h_v;
53173 duk_hobject *h_obj;
53174 duk_propdesc desc;
53175 duk_bool_t ret;
53176
53177 /* coercion order matters */
53178 h_v = duk_to_hstring(ctx, 0);
53179 DUK_ASSERT(h_v != NULL);
53180
53181 h_obj = duk_push_this_coercible_to_object(ctx);
53182 DUK_ASSERT(h_obj != NULL);
53183
11fdf7f2 53184 ret = duk_hobject_get_own_propdesc(thr, h_obj, h_v, &desc, 0 /*flags*/); /* don't push value */
7c673cae
FG
53185
53186 duk_push_boolean(ctx, ret && ((desc.flags & required_desc_flags) == required_desc_flags));
53187 return 1;
53188}
53189
53190/*
53191 * Object.seal() and Object.freeze() (E5 Sections 15.2.3.8 and 15.2.3.9)
53192 *
53193 * Since the algorithms are similar, a helper provides both functions.
53194 * Freezing is essentially sealing + making plain properties non-writable.
53195 *
53196 * Note: virtual (non-concrete) properties which are non-configurable but
53197 * writable would pose some problems, but such properties do not currently
53198 * exist (all virtual properties are non-configurable and non-writable).
53199 * If they did exist, the non-configurability does NOT prevent them from
53200 * becoming non-writable. However, this change should be recorded somehow
53201 * so that it would turn up (e.g. when getting the property descriptor),
53202 * requiring some additional flags in the object.
53203 */
53204
53205DUK_INTERNAL void duk_hobject_object_seal_freeze_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_freeze) {
53206 duk_uint_fast32_t i;
53207
53208 DUK_ASSERT(thr != NULL);
53209 DUK_ASSERT(thr->heap != NULL);
53210 DUK_ASSERT(obj != NULL);
53211
53212 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
53213
11fdf7f2
TL
53214#if defined(DUK_USE_ROM_OBJECTS)
53215 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
53216 DUK_DD(DUK_DDPRINT("attempt to seal/freeze a readonly object, reject"));
53217 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
53218 }
53219#endif
53220
7c673cae
FG
53221 /*
53222 * Abandon array part because all properties must become non-configurable.
53223 * Note that this is now done regardless of whether this is always the case
53224 * (skips check, but performance problem if caller would do this many times
53225 * for the same object; not likely).
53226 */
53227
53228 duk__abandon_array_checked(thr, obj);
53229 DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) == 0);
53230
53231 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
53232 duk_uint8_t *fp;
53233
53234 /* since duk__abandon_array_checked() causes a resize, there should be no gaps in keys */
53235 DUK_ASSERT(DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i) != NULL);
53236
53237 /* avoid multiple computations of flags address; bypasses macros */
53238 fp = DUK_HOBJECT_E_GET_FLAGS_PTR(thr->heap, obj, i);
53239 if (is_freeze && !((*fp) & DUK_PROPDESC_FLAG_ACCESSOR)) {
53240 *fp &= ~(DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_CONFIGURABLE);
53241 } else {
53242 *fp &= ~DUK_PROPDESC_FLAG_CONFIGURABLE;
53243 }
53244 }
53245
53246 DUK_HOBJECT_CLEAR_EXTENSIBLE(obj);
53247
53248 /* no need to compact since we already did that in duk__abandon_array_checked()
53249 * (regardless of whether an array part existed or not.
53250 */
53251
53252 return;
53253}
53254
53255/*
53256 * Object.isSealed() and Object.isFrozen() (E5 Sections 15.2.3.11, 15.2.3.13)
53257 *
53258 * Since the algorithms are similar, a helper provides both functions.
53259 * Freezing is essentially sealing + making plain properties non-writable.
53260 *
53261 * Note: all virtual (non-concrete) properties are currently non-configurable
53262 * and non-writable (and there are no accessor virtual properties), so they don't
53263 * need to be considered here now.
53264 */
53265
53266DUK_INTERNAL duk_bool_t duk_hobject_object_is_sealed_frozen_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_frozen) {
53267 duk_uint_fast32_t i;
53268
53269 DUK_ASSERT(obj != NULL);
53270 DUK_UNREF(thr);
53271
53272 /* Note: no allocation pressure, no need to check refcounts etc */
53273
53274 /* must not be extensible */
53275 if (DUK_HOBJECT_HAS_EXTENSIBLE(obj)) {
53276 return 0;
53277 }
53278
53279 /* all virtual properties are non-configurable and non-writable */
53280
53281 /* entry part must not contain any configurable properties, or
53282 * writable properties (if is_frozen).
53283 */
53284 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
53285 duk_small_uint_t flags;
53286
53287 if (!DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i)) {
53288 continue;
53289 }
53290
53291 /* avoid multiple computations of flags address; bypasses macros */
53292 flags = (duk_small_uint_t) DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, i);
53293
53294 if (flags & DUK_PROPDESC_FLAG_CONFIGURABLE) {
53295 return 0;
53296 }
53297 if (is_frozen &&
53298 !(flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
53299 (flags & DUK_PROPDESC_FLAG_WRITABLE)) {
53300 return 0;
53301 }
53302 }
53303
53304 /* array part must not contain any non-unused properties, as they would
53305 * be configurable and writable.
53306 */
53307 for (i = 0; i < DUK_HOBJECT_GET_ASIZE(obj); i++) {
53308 duk_tval *tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i);
11fdf7f2 53309 if (!DUK_TVAL_IS_UNUSED(tv)) {
7c673cae
FG
53310 return 0;
53311 }
53312 }
53313
53314 return 1;
53315}
53316
53317/*
53318 * Object.preventExtensions() and Object.isExtensible() (E5 Sections 15.2.3.10, 15.2.3.13)
53319 *
53320 * Not needed, implemented by macros DUK_HOBJECT_{HAS,CLEAR,SET}_EXTENSIBLE
53321 * and the Object built-in bindings.
53322 */
53323
53324/* Undefine local defines */
53325
53326#undef DUK__NO_ARRAY_INDEX
53327#undef DUK__HASH_INITIAL
53328#undef DUK__HASH_PROBE_STEP
53329#undef DUK__HASH_UNUSED
53330#undef DUK__HASH_DELETED
53331#undef DUK__VALSTACK_SPACE
7c673cae
FG
53332/*
53333 * Misc support functions
53334 */
53335
53336/* include removed: duk_internal.h */
53337
53338DUK_INTERNAL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos) {
53339 duk_uint32_t boff;
53340 const duk_uint8_t *p, *p_start, *p_end;
53341 duk_ucodepoint_t cp;
53342
53343 /* Caller must check character offset to be inside the string. */
53344 DUK_ASSERT(thr != NULL);
53345 DUK_ASSERT(h != NULL);
53346 DUK_ASSERT_DISABLE(pos >= 0); /* unsigned */
53347 DUK_ASSERT(pos < (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h));
53348
53349 boff = duk_heap_strcache_offset_char2byte(thr, h, (duk_uint32_t) pos);
53350 DUK_DDD(DUK_DDDPRINT("charCodeAt: pos=%ld -> boff=%ld, str=%!O",
53351 (long) pos, (long) boff, (duk_heaphdr *) h));
53352 DUK_ASSERT_DISABLE(boff >= 0);
53353 DUK_ASSERT(boff < DUK_HSTRING_GET_BYTELEN(h));
53354
53355 p_start = DUK_HSTRING_GET_DATA(h);
53356 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h);
53357 p = p_start + boff;
53358 DUK_DDD(DUK_DDDPRINT("p_start=%p, p_end=%p, p=%p",
11fdf7f2
TL
53359 (const void *) p_start, (const void *) p_end,
53360 (const void *) p));
7c673cae
FG
53361
53362 /* This may throw an error though not for valid E5 strings. */
53363 cp = duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
53364 return cp;
53365}
11fdf7f2
TL
53366
53367#if !defined(DUK_USE_HSTRING_CLEN)
53368DUK_INTERNAL duk_size_t duk_hstring_get_charlen(duk_hstring *h) {
53369 if (DUK_HSTRING_HAS_ASCII(h)) {
53370 /* Most practical strings will go here. */
53371 return DUK_HSTRING_GET_BYTELEN(h);
53372 } else {
53373 return duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
53374 }
53375}
53376#endif /* !DUK_USE_HSTRING_CLEN */
7c673cae
FG
53377/*
53378 * duk_hthread allocation and freeing.
53379 */
53380
53381/* include removed: duk_internal.h */
53382
53383/*
53384 * Allocate initial stacks for a thread. Note that 'thr' must be reachable
53385 * as a garbage collection may be triggered by the allocation attempts.
53386 * Returns zero (without leaking memory) if init fails.
53387 */
53388
53389DUK_INTERNAL duk_bool_t duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr) {
53390 duk_size_t alloc_size;
53391 duk_size_t i;
53392
53393 DUK_ASSERT(heap != NULL);
53394 DUK_ASSERT(thr != NULL);
53395 DUK_ASSERT(thr->valstack == NULL);
53396 DUK_ASSERT(thr->valstack_end == NULL);
53397 DUK_ASSERT(thr->valstack_bottom == NULL);
53398 DUK_ASSERT(thr->valstack_top == NULL);
53399 DUK_ASSERT(thr->callstack == NULL);
53400 DUK_ASSERT(thr->catchstack == NULL);
53401
53402 /* valstack */
53403 alloc_size = sizeof(duk_tval) * DUK_VALSTACK_INITIAL_SIZE;
53404 thr->valstack = (duk_tval *) DUK_ALLOC(heap, alloc_size);
53405 if (!thr->valstack) {
53406 goto fail;
53407 }
53408 DUK_MEMZERO(thr->valstack, alloc_size);
53409 thr->valstack_end = thr->valstack + DUK_VALSTACK_INITIAL_SIZE;
11fdf7f2
TL
53410#if !defined(DUK_USE_PREFER_SIZE)
53411 thr->valstack_size = DUK_VALSTACK_INITIAL_SIZE;
53412#endif
7c673cae
FG
53413 thr->valstack_bottom = thr->valstack;
53414 thr->valstack_top = thr->valstack;
53415
53416 for (i = 0; i < DUK_VALSTACK_INITIAL_SIZE; i++) {
11fdf7f2 53417 DUK_TVAL_SET_UNDEFINED(&thr->valstack[i]);
7c673cae
FG
53418 }
53419
53420 /* callstack */
53421 alloc_size = sizeof(duk_activation) * DUK_CALLSTACK_INITIAL_SIZE;
53422 thr->callstack = (duk_activation *) DUK_ALLOC(heap, alloc_size);
53423 if (!thr->callstack) {
53424 goto fail;
53425 }
53426 DUK_MEMZERO(thr->callstack, alloc_size);
53427 thr->callstack_size = DUK_CALLSTACK_INITIAL_SIZE;
53428 DUK_ASSERT(thr->callstack_top == 0);
53429
53430 /* catchstack */
53431 alloc_size = sizeof(duk_catcher) * DUK_CATCHSTACK_INITIAL_SIZE;
53432 thr->catchstack = (duk_catcher *) DUK_ALLOC(heap, alloc_size);
53433 if (!thr->catchstack) {
53434 goto fail;
53435 }
53436 DUK_MEMZERO(thr->catchstack, alloc_size);
53437 thr->catchstack_size = DUK_CATCHSTACK_INITIAL_SIZE;
53438 DUK_ASSERT(thr->catchstack_top == 0);
53439
53440 return 1;
53441
53442 fail:
53443 DUK_FREE(heap, thr->valstack);
53444 DUK_FREE(heap, thr->callstack);
53445 DUK_FREE(heap, thr->catchstack);
53446
53447 thr->valstack = NULL;
53448 thr->callstack = NULL;
53449 thr->catchstack = NULL;
53450 return 0;
53451}
53452
53453/* For indirect allocs. */
53454
53455DUK_INTERNAL void *duk_hthread_get_valstack_ptr(duk_heap *heap, void *ud) {
53456 duk_hthread *thr = (duk_hthread *) ud;
53457 DUK_UNREF(heap);
53458 return (void *) thr->valstack;
53459}
53460
53461DUK_INTERNAL void *duk_hthread_get_callstack_ptr(duk_heap *heap, void *ud) {
53462 duk_hthread *thr = (duk_hthread *) ud;
53463 DUK_UNREF(heap);
53464 return (void *) thr->callstack;
53465}
53466
53467DUK_INTERNAL void *duk_hthread_get_catchstack_ptr(duk_heap *heap, void *ud) {
53468 duk_hthread *thr = (duk_hthread *) ud;
53469 DUK_UNREF(heap);
53470 return (void *) thr->catchstack;
53471}
7c673cae
FG
53472/*
53473 * Initialize built-in objects. Current thread must have a valstack
53474 * and initialization errors may longjmp, so a setjmp() catch point
53475 * must exist.
53476 */
53477
53478/* include removed: duk_internal.h */
53479
53480/*
53481 * Encoding constants, must match genbuiltins.py
53482 */
53483
53484#define DUK__CLASS_BITS 5
53485#define DUK__BIDX_BITS 7
11fdf7f2 53486#define DUK__STRIDX_BITS 9 /* XXX: try to optimize to 8 (would now be possible, <200 used) */
7c673cae
FG
53487#define DUK__NATIDX_BITS 8
53488#define DUK__NUM_NORMAL_PROPS_BITS 6
53489#define DUK__NUM_FUNC_PROPS_BITS 6
53490#define DUK__PROP_FLAGS_BITS 3
53491#define DUK__STRING_LENGTH_BITS 8
53492#define DUK__STRING_CHAR_BITS 7
53493#define DUK__LENGTH_PROP_BITS 3
53494#define DUK__NARGS_BITS 3
53495#define DUK__PROP_TYPE_BITS 3
53496#define DUK__MAGIC_BITS 16
53497
53498#define DUK__NARGS_VARARGS_MARKER 0x07
53499#define DUK__NO_CLASS_MARKER 0x00 /* 0 = DUK_HOBJECT_CLASS_UNUSED */
53500#define DUK__NO_BIDX_MARKER 0x7f
53501#define DUK__NO_STRIDX_MARKER 0xff
53502
53503#define DUK__PROP_TYPE_DOUBLE 0
53504#define DUK__PROP_TYPE_STRING 1
53505#define DUK__PROP_TYPE_STRIDX 2
53506#define DUK__PROP_TYPE_BUILTIN 3
53507#define DUK__PROP_TYPE_UNDEFINED 4
53508#define DUK__PROP_TYPE_BOOLEAN_TRUE 5
53509#define DUK__PROP_TYPE_BOOLEAN_FALSE 6
53510#define DUK__PROP_TYPE_ACCESSOR 7
53511
53512/*
53513 * Create built-in objects by parsing an init bitstream generated
53514 * by genbuiltins.py.
53515 */
53516
11fdf7f2
TL
53517#if defined(DUK_USE_ROM_OBJECTS)
53518#if defined(DUK_USE_ROM_GLOBAL_CLONE) || defined(DUK_USE_ROM_GLOBAL_INHERIT)
53519DUK_LOCAL void duk__duplicate_ram_global_object(duk_hthread *thr) {
53520 duk_context *ctx;
53521 duk_hobject *h1;
53522#if defined(DUK_USE_ROM_GLOBAL_CLONE)
53523 duk_hobject *h2;
53524 duk_uint8_t *props;
53525 duk_size_t alloc_size;
53526#endif
53527
53528 ctx = (duk_context *) thr;
53529
53530 /* XXX: refactor into internal helper, duk_clone_hobject() */
53531
53532#if defined(DUK_USE_ROM_GLOBAL_INHERIT)
53533 /* Inherit from ROM-based global object: less RAM usage, less transparent. */
53534 duk_push_object_helper(ctx,
53535 DUK_HOBJECT_FLAG_EXTENSIBLE |
53536 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL),
53537 DUK_BIDX_GLOBAL);
53538 h1 = duk_get_hobject(ctx, -1);
53539 DUK_ASSERT(h1 != NULL);
53540#elif defined(DUK_USE_ROM_GLOBAL_CLONE)
53541 /* Clone the properties of the ROM-based global object to create a
53542 * fully RAM-based global object. Uses more memory than the inherit
53543 * model but more compliant.
53544 */
53545 duk_push_object_helper(ctx,
53546 DUK_HOBJECT_FLAG_EXTENSIBLE |
53547 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL),
53548 DUK_BIDX_OBJECT_PROTOTYPE);
53549 h1 = duk_get_hobject(ctx, -1);
53550 DUK_ASSERT(h1 != NULL);
53551 h2 = thr->builtins[DUK_BIDX_GLOBAL];
53552 DUK_ASSERT(h2 != NULL);
53553
53554 /* Copy the property table verbatim; this handles attributes etc.
53555 * For ROM objects it's not necessary (or possible) to update
53556 * refcounts so leave them as is.
53557 */
53558 alloc_size = DUK_HOBJECT_P_ALLOC_SIZE(h2);
53559 DUK_ASSERT(alloc_size > 0);
53560 props = DUK_ALLOC(thr->heap, alloc_size);
53561 if (!props) {
53562 DUK_ERROR_ALLOC_DEFMSG(thr);
53563 return;
53564 }
53565 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h2) != NULL);
53566 DUK_MEMCPY((void *) props, (const void *) DUK_HOBJECT_GET_PROPS(thr->heap, h2), alloc_size);
53567
53568 /* XXX: keep property attributes or tweak them here?
53569 * Properties will now be non-configurable even when they're
53570 * normally configurable for the global object.
53571 */
53572
53573 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h1) == NULL);
53574 DUK_HOBJECT_SET_PROPS(thr->heap, h1, props);
53575 DUK_HOBJECT_SET_ESIZE(h1, DUK_HOBJECT_GET_ESIZE(h2));
53576 DUK_HOBJECT_SET_ENEXT(h1, DUK_HOBJECT_GET_ENEXT(h2));
53577 DUK_HOBJECT_SET_ASIZE(h1, DUK_HOBJECT_GET_ASIZE(h2));
53578 DUK_HOBJECT_SET_HSIZE(h1, DUK_HOBJECT_GET_HSIZE(h2));
53579#else
53580#error internal error in defines
53581#endif
53582
53583 duk_hobject_compact_props(thr, h1);
53584 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
53585 DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL])); /* no need to decref */
53586 thr->builtins[DUK_BIDX_GLOBAL] = h1;
53587 DUK_HOBJECT_INCREF(thr, h1);
53588 DUK_D(DUK_DPRINT("duplicated global object: %!O", h1));
53589
53590
53591 /* Create a fresh object environment for the global scope. This is
53592 * needed so that the global scope points to the newly created RAM-based
53593 * global object.
53594 */
53595 duk_push_object_helper(ctx,
53596 DUK_HOBJECT_FLAG_EXTENSIBLE |
53597 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV),
53598 -1); /* no prototype */
53599 h1 = duk_get_hobject(ctx, -1);
53600 DUK_ASSERT(h1 != NULL);
53601 duk_dup(ctx, -2); /* -> [ ... new_global new_globalenv new_global ] */
53602 duk_xdef_prop_stridx(thr, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
53603 /* provideThis=false */
53604
53605 duk_hobject_compact_props(thr, h1);
53606 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL);
53607 DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL_ENV])); /* no need to decref */
53608 thr->builtins[DUK_BIDX_GLOBAL_ENV] = h1;
53609 DUK_HOBJECT_INCREF(thr, h1);
53610 DUK_D(DUK_DPRINT("duplicated global env: %!O", h1));
53611
53612 duk_pop_2(ctx);
53613}
53614#endif /* DUK_USE_ROM_GLOBAL_CLONE || DUK_USE_ROM_GLOBAL_INHERIT */
53615
53616DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
53617 /* Setup builtins from ROM objects. All heaps/threads will share
53618 * the same readonly objects.
53619 */
53620 duk_small_uint_t i;
53621
53622 for (i = 0; i < DUK_NUM_BUILTINS; i++) {
53623 duk_hobject *h;
53624 h = (duk_hobject *) DUK_LOSE_CONST(duk_rom_builtins_bidx[i]);
53625 DUK_ASSERT(h != NULL);
53626 thr->builtins[i] = h;
53627 }
53628
53629#if defined(DUK_USE_ROM_GLOBAL_CLONE) || defined(DUK_USE_ROM_GLOBAL_INHERIT)
53630 /* By default the global object is read-only which is often much
53631 * more of an issue than having read-only built-in objects (like
53632 * RegExp, Date, etc). Use a RAM-based copy of the global object
53633 * and the global environment object for convenience.
53634 */
53635 duk__duplicate_ram_global_object(thr);
53636#endif
53637}
53638#else /* DUK_USE_ROM_OBJECTS */
53639DUK_LOCAL void duk__push_stridx(duk_context *ctx, duk_bitdecoder_ctx *bd) {
53640 duk_small_uint_t n;
53641
53642 n = (duk_small_uint_t) duk_bd_decode(bd, DUK__STRIDX_BITS);
53643 DUK_ASSERT_DISABLE(n >= 0); /* unsigned */
53644 DUK_ASSERT(n < DUK_HEAP_NUM_STRINGS);
53645 duk_push_hstring_stridx(ctx, n);
53646}
53647DUK_LOCAL void duk__push_string(duk_context *ctx, duk_bitdecoder_ctx *bd) {
53648 duk_small_uint_t n;
53649 duk_small_uint_t i;
53650 duk_uint8_t *p;
53651
53652 n = (duk_small_uint_t) duk_bd_decode(bd, DUK__STRING_LENGTH_BITS);
53653 p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, n);
53654 for (i = 0; i < n; i++) {
53655 *p++ = (duk_uint8_t) duk_bd_decode(bd, DUK__STRING_CHAR_BITS);
53656 }
53657 duk_to_string(ctx, -1);
53658}
53659DUK_LOCAL void duk__push_stridx_or_string(duk_context *ctx, duk_bitdecoder_ctx *bd) {
53660 if (duk_bd_decode_flag(bd)) {
53661 duk__push_string(ctx, bd);
53662 } else {
53663 duk__push_stridx(ctx, bd);
53664 }
53665}
53666DUK_LOCAL void duk__push_double(duk_context *ctx, duk_bitdecoder_ctx *bd) {
53667 duk_double_union du;
53668 duk_small_uint_t i;
53669
53670 for (i = 0; i < 8; i++) {
53671 /* Encoding endianness must match target memory layout,
53672 * build scripts and genbuiltins.py must ensure this.
53673 */
53674 du.uc[i] = (duk_uint8_t) duk_bd_decode(bd, 8);
53675 }
53676
53677 duk_push_number(ctx, du.d); /* push operation normalizes NaNs */
53678}
53679
7c673cae
FG
53680DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
53681 duk_context *ctx = (duk_context *) thr;
53682 duk_bitdecoder_ctx bd_ctx;
53683 duk_bitdecoder_ctx *bd = &bd_ctx; /* convenience */
53684 duk_hobject *h;
53685 duk_small_uint_t i, j;
53686
11fdf7f2 53687 DUK_D(DUK_DPRINT("INITBUILTINS BEGIN: DUK_NUM_BUILTINS=%d, DUK_NUM_BUILTINS_ALL=%d", (int) DUK_NUM_BUILTINS, (int) DUK_NUM_ALL_BUILTINS));
7c673cae
FG
53688
53689 DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
53690 bd->data = (const duk_uint8_t *) duk_builtins_data;
53691 bd->length = (duk_size_t) DUK_BUILTINS_DATA_LENGTH;
53692
53693 /*
53694 * First create all built-in bare objects on the empty valstack.
7c673cae 53695 *
11fdf7f2
TL
53696 * Built-ins in the index range [0,DUK_NUM_BUILTINS-1] have value
53697 * stack indices matching their eventual thr->builtins[] index.
53698 *
53699 * Built-ins in the index range [DUK_NUM_BUILTINS,DUK_NUM_ALL_BUILTINS]
53700 * will exist on the value stack during init but won't be placed
53701 * into thr->builtins[]. These are objects referenced in some way
53702 * from thr->builtins[] roots but which don't need to be indexed by
53703 * Duktape through thr->builtins[] (e.g. user custom objects).
7c673cae
FG
53704 */
53705
11fdf7f2 53706 duk_require_stack(ctx, DUK_NUM_ALL_BUILTINS);
7c673cae
FG
53707
53708 DUK_DD(DUK_DDPRINT("create empty built-ins"));
53709 DUK_ASSERT_TOP(ctx, 0);
11fdf7f2 53710 for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
7c673cae
FG
53711 duk_small_uint_t class_num;
53712 duk_small_int_t len = -1; /* must be signed */
53713
53714 class_num = (duk_small_uint_t) duk_bd_decode(bd, DUK__CLASS_BITS);
53715 len = (duk_small_int_t) duk_bd_decode_flagged(bd, DUK__LENGTH_PROP_BITS, (duk_int32_t) -1 /*def_value*/);
53716
53717 if (class_num == DUK_HOBJECT_CLASS_FUNCTION) {
53718 duk_small_uint_t natidx;
7c673cae
FG
53719 duk_int_t c_nargs; /* must hold DUK_VARARGS */
53720 duk_c_function c_func;
53721 duk_int16_t magic;
53722
53723 DUK_DDD(DUK_DDDPRINT("len=%ld", (long) len));
53724 DUK_ASSERT(len >= 0);
53725
53726 natidx = (duk_small_uint_t) duk_bd_decode(bd, DUK__NATIDX_BITS);
7c673cae
FG
53727 c_func = duk_bi_native_functions[natidx];
53728
53729 c_nargs = (duk_small_uint_t) duk_bd_decode_flagged(bd, DUK__NARGS_BITS, len /*def_value*/);
53730 if (c_nargs == DUK__NARGS_VARARGS_MARKER) {
53731 c_nargs = DUK_VARARGS;
53732 }
53733
53734 /* XXX: set magic directly here? (it could share the c_nargs arg) */
53735 duk_push_c_function_noexotic(ctx, c_func, c_nargs);
53736
53737 h = duk_require_hobject(ctx, -1);
53738 DUK_ASSERT(h != NULL);
53739
53740 /* Currently all built-in native functions are strict.
53741 * duk_push_c_function() now sets strict flag, so
53742 * assert for it.
53743 */
53744 DUK_ASSERT(DUK_HOBJECT_HAS_STRICT(h));
53745
53746 /* XXX: function properties */
53747
11fdf7f2
TL
53748 /* Built-in 'name' is not writable by default. Function '.name'
53749 * is writable to allow user code to set a '.name' on a native
53750 * function.
53751 */
53752 duk__push_stridx_or_string(ctx, bd);
53753 duk_xdef_prop_stridx(ctx,
53754 -2,
53755 DUK_STRIDX_NAME,
53756 (i == DUK_BIDX_FUNCTION_PROTOTYPE) ?
53757 DUK_PROPDESC_FLAGS_W : DUK_PROPDESC_FLAGS_NONE);
7c673cae
FG
53758
53759 /* Almost all global level Function objects are constructable
53760 * but not all: Function.prototype is a non-constructable,
53761 * callable Function.
53762 */
53763 if (duk_bd_decode_flag(bd)) {
53764 DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE(h));
53765 } else {
53766 DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h);
53767 }
53768
53769 /* Cast converts magic to 16-bit signed value */
53770 magic = (duk_int16_t) duk_bd_decode_flagged(bd, DUK__MAGIC_BITS, 0 /*def_value*/);
53771 ((duk_hnativefunction *) h)->magic = magic;
53772 } else {
53773 /* XXX: ARRAY_PART for Array prototype? */
53774
53775 duk_push_object_helper(ctx,
53776 DUK_HOBJECT_FLAG_EXTENSIBLE,
53777 -1); /* no prototype or class yet */
53778
53779 h = duk_require_hobject(ctx, -1);
53780 DUK_ASSERT(h != NULL);
53781 }
53782
53783 DUK_HOBJECT_SET_CLASS_NUMBER(h, class_num);
53784
11fdf7f2
TL
53785 if (i < DUK_NUM_BUILTINS) {
53786 thr->builtins[i] = h;
53787 DUK_HOBJECT_INCREF(thr, &h->hdr);
53788 }
7c673cae
FG
53789
53790 if (len >= 0) {
53791 /*
53792 * For top-level objects, 'length' property has the following
53793 * default attributes: non-writable, non-enumerable, non-configurable
53794 * (E5 Section 15).
53795 *
53796 * However, 'length' property for Array.prototype has attributes
53797 * expected of an Array instance which are different: writable,
53798 * non-enumerable, non-configurable (E5 Section 15.4.5.2).
53799 *
53800 * This is currently determined implicitly based on class; there are
53801 * no attribute flags in the init data.
53802 */
53803
53804 duk_push_int(ctx, len);
53805 duk_xdef_prop_stridx(ctx,
53806 -2,
53807 DUK_STRIDX_LENGTH,
53808 (class_num == DUK_HOBJECT_CLASS_ARRAY ? /* only Array.prototype matches */
53809 DUK_PROPDESC_FLAGS_W : DUK_PROPDESC_FLAGS_NONE));
53810 }
53811
53812 /* enable exotic behaviors last */
53813
53814 if (class_num == DUK_HOBJECT_CLASS_ARRAY) {
53815 DUK_HOBJECT_SET_EXOTIC_ARRAY(h);
53816 }
53817 if (class_num == DUK_HOBJECT_CLASS_STRING) {
53818 DUK_HOBJECT_SET_EXOTIC_STRINGOBJ(h);
53819 }
53820
53821 /* some assertions */
53822
53823 DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h));
53824 /* DUK_HOBJECT_FLAG_CONSTRUCTABLE varies */
53825 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(h));
53826 DUK_ASSERT(!DUK_HOBJECT_HAS_COMPILEDFUNCTION(h));
53827 /* DUK_HOBJECT_FLAG_NATIVEFUNCTION varies */
53828 DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(h));
53829 DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(h)); /* currently, even for Array.prototype */
53830 /* DUK_HOBJECT_FLAG_STRICT varies */
53831 DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(h) || /* all native functions have NEWENV */
53832 DUK_HOBJECT_HAS_NEWENV(h));
53833 DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(h));
53834 DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(h));
53835 DUK_ASSERT(!DUK_HOBJECT_HAS_ENVRECCLOSED(h));
53836 /* DUK_HOBJECT_FLAG_EXOTIC_ARRAY varies */
53837 /* DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ varies */
53838 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h));
53839
53840 DUK_DDD(DUK_DDDPRINT("created built-in %ld, class=%ld, length=%ld", (long) i, (long) class_num, (long) len));
53841 }
53842
53843 /*
53844 * Then decode the builtins init data (see genbuiltins.py) to
53845 * init objects
53846 */
53847
53848 DUK_DD(DUK_DDPRINT("initialize built-in object properties"));
11fdf7f2 53849 for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
7c673cae
FG
53850 duk_small_uint_t t;
53851 duk_small_uint_t num;
53852
53853 DUK_DDD(DUK_DDDPRINT("initializing built-in object at index %ld", (long) i));
11fdf7f2
TL
53854 h = duk_require_hobject(ctx, i);
53855 DUK_ASSERT(h != NULL);
7c673cae
FG
53856
53857 t = (duk_small_uint_t) duk_bd_decode(bd, DUK__BIDX_BITS);
53858 if (t != DUK__NO_BIDX_MARKER) {
53859 DUK_DDD(DUK_DDDPRINT("set internal prototype: built-in %ld", (long) t));
11fdf7f2 53860 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, duk_require_hobject(ctx, t));
7c673cae
FG
53861 }
53862
53863 t = (duk_small_uint_t) duk_bd_decode(bd, DUK__BIDX_BITS);
53864 if (t != DUK__NO_BIDX_MARKER) {
53865 /* 'prototype' property for all built-in objects (which have it) has attributes:
53866 * [[Writable]] = false,
53867 * [[Enumerable]] = false,
53868 * [[Configurable]] = false
53869 */
53870 DUK_DDD(DUK_DDDPRINT("set external prototype: built-in %ld", (long) t));
53871 duk_xdef_prop_stridx_builtin(ctx, i, DUK_STRIDX_PROTOTYPE, t, DUK_PROPDESC_FLAGS_NONE);
53872 }
53873
53874 t = (duk_small_uint_t) duk_bd_decode(bd, DUK__BIDX_BITS);
53875 if (t != DUK__NO_BIDX_MARKER) {
53876 /* 'constructor' property for all built-in objects (which have it) has attributes:
53877 * [[Writable]] = true,
53878 * [[Enumerable]] = false,
53879 * [[Configurable]] = true
53880 */
53881 DUK_DDD(DUK_DDDPRINT("set external constructor: built-in %ld", (long) t));
53882 duk_xdef_prop_stridx_builtin(ctx, i, DUK_STRIDX_CONSTRUCTOR, t, DUK_PROPDESC_FLAGS_WC);
53883 }
53884
53885 /* normal valued properties */
53886 num = (duk_small_uint_t) duk_bd_decode(bd, DUK__NUM_NORMAL_PROPS_BITS);
53887 DUK_DDD(DUK_DDDPRINT("built-in object %ld, %ld normal valued properties", (long) i, (long) num));
53888 for (j = 0; j < num; j++) {
7c673cae
FG
53889 duk_small_uint_t prop_flags;
53890
11fdf7f2 53891 duk__push_stridx_or_string(ctx, bd);
7c673cae
FG
53892
53893 /*
53894 * Property attribute defaults are defined in E5 Section 15 (first
53895 * few pages); there is a default for all properties and a special
53896 * default for 'length' properties. Variation from the defaults is
53897 * signaled using a single flag bit in the bitstream.
53898 */
53899
53900 if (duk_bd_decode_flag(bd)) {
53901 prop_flags = (duk_small_uint_t) duk_bd_decode(bd, DUK__PROP_FLAGS_BITS);
53902 } else {
11fdf7f2 53903 prop_flags = DUK_PROPDESC_FLAGS_WC;
7c673cae
FG
53904 }
53905
53906 t = (duk_small_uint_t) duk_bd_decode(bd, DUK__PROP_TYPE_BITS);
53907
11fdf7f2
TL
53908 DUK_DDD(DUK_DDDPRINT("built-in %ld, normal-valued property %ld, key %!T, flags 0x%02lx, type %ld",
53909 (long) i, (long) j, duk_get_tval(ctx, -1), (unsigned long) prop_flags, (long) t));
7c673cae
FG
53910
53911 switch (t) {
53912 case DUK__PROP_TYPE_DOUBLE: {
11fdf7f2 53913 duk__push_double(ctx, bd);
7c673cae
FG
53914 break;
53915 }
53916 case DUK__PROP_TYPE_STRING: {
11fdf7f2 53917 duk__push_string(ctx, bd);
7c673cae
FG
53918 break;
53919 }
53920 case DUK__PROP_TYPE_STRIDX: {
11fdf7f2 53921 duk__push_stridx(ctx, bd);
7c673cae
FG
53922 break;
53923 }
53924 case DUK__PROP_TYPE_BUILTIN: {
53925 duk_small_uint_t bidx;
53926
53927 bidx = (duk_small_uint_t) duk_bd_decode(bd, DUK__BIDX_BITS);
53928 DUK_ASSERT(bidx != DUK__NO_BIDX_MARKER);
53929 duk_dup(ctx, (duk_idx_t) bidx);
53930 break;
53931 }
53932 case DUK__PROP_TYPE_UNDEFINED: {
53933 duk_push_undefined(ctx);
53934 break;
53935 }
53936 case DUK__PROP_TYPE_BOOLEAN_TRUE: {
53937 duk_push_true(ctx);
53938 break;
53939 }
53940 case DUK__PROP_TYPE_BOOLEAN_FALSE: {
53941 duk_push_false(ctx);
53942 break;
53943 }
53944 case DUK__PROP_TYPE_ACCESSOR: {
53945 duk_small_uint_t natidx_getter = (duk_small_uint_t) duk_bd_decode(bd, DUK__NATIDX_BITS);
53946 duk_small_uint_t natidx_setter = (duk_small_uint_t) duk_bd_decode(bd, DUK__NATIDX_BITS);
53947 duk_c_function c_func_getter;
53948 duk_c_function c_func_setter;
53949
53950 /* XXX: this is a bit awkward because there is no exposed helper
53951 * in the API style, only this internal helper.
53952 */
11fdf7f2
TL
53953 DUK_DDD(DUK_DDDPRINT("built-in accessor property: objidx=%ld, key=%!T, getteridx=%ld, setteridx=%ld, flags=0x%04lx",
53954 (long) i, duk_get_tval(ctx, -1), (long) natidx_getter, (long) natidx_setter, (unsigned long) prop_flags));
7c673cae
FG
53955
53956 c_func_getter = duk_bi_native_functions[natidx_getter];
53957 c_func_setter = duk_bi_native_functions[natidx_setter];
53958 duk_push_c_function_noconstruct_noexotic(ctx, c_func_getter, 0); /* always 0 args */
53959 duk_push_c_function_noconstruct_noexotic(ctx, c_func_setter, 1); /* always 1 arg */
53960
11fdf7f2
TL
53961 /* XXX: magic for getter/setter? use duk_def_prop()? */
53962
53963 DUK_ASSERT((prop_flags & DUK_PROPDESC_FLAG_WRITABLE) == 0); /* genbuiltins.py ensures */
7c673cae
FG
53964
53965 prop_flags |= DUK_PROPDESC_FLAG_ACCESSOR; /* accessor flag not encoded explicitly */
53966 duk_hobject_define_accessor_internal(thr,
53967 duk_require_hobject(ctx, i),
11fdf7f2 53968 duk_get_hstring(ctx, -3),
7c673cae
FG
53969 duk_require_hobject(ctx, -2),
53970 duk_require_hobject(ctx, -1),
53971 prop_flags);
11fdf7f2 53972 duk_pop_3(ctx); /* key, getter and setter, now reachable through object */
7c673cae
FG
53973 goto skip_value;
53974 }
53975 default: {
53976 /* exhaustive */
53977 DUK_UNREACHABLE();
53978 }
53979 }
53980
53981 DUK_ASSERT((prop_flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0);
11fdf7f2 53982 duk_xdef_prop(ctx, i, prop_flags);
7c673cae
FG
53983
53984 skip_value:
53985 continue; /* avoid empty label at the end of a compound statement */
53986 }
53987
53988 /* native function properties */
53989 num = (duk_small_uint_t) duk_bd_decode(bd, DUK__NUM_FUNC_PROPS_BITS);
53990 DUK_DDD(DUK_DDDPRINT("built-in object %ld, %ld function valued properties", (long) i, (long) num));
53991 for (j = 0; j < num; j++) {
11fdf7f2 53992 duk_hstring *h_key;
7c673cae
FG
53993 duk_small_uint_t natidx;
53994 duk_int_t c_nargs; /* must hold DUK_VARARGS */
53995 duk_small_uint_t c_length;
53996 duk_int16_t magic;
53997 duk_c_function c_func;
53998 duk_hnativefunction *h_func;
53999#if defined(DUK_USE_LIGHTFUNC_BUILTINS)
54000 duk_small_int_t lightfunc_eligible;
54001#endif
54002
11fdf7f2
TL
54003 duk__push_stridx_or_string(ctx, bd);
54004 h_key = duk_get_hstring(ctx, -1);
54005 DUK_ASSERT(h_key != NULL);
54006 DUK_UNREF(h_key);
7c673cae
FG
54007 natidx = (duk_small_uint_t) duk_bd_decode(bd, DUK__NATIDX_BITS);
54008
54009 c_length = (duk_small_uint_t) duk_bd_decode(bd, DUK__LENGTH_PROP_BITS);
54010 c_nargs = (duk_int_t) duk_bd_decode_flagged(bd, DUK__NARGS_BITS, (duk_int32_t) c_length /*def_value*/);
54011 if (c_nargs == DUK__NARGS_VARARGS_MARKER) {
54012 c_nargs = DUK_VARARGS;
54013 }
54014
54015 c_func = duk_bi_native_functions[natidx];
54016
11fdf7f2
TL
54017 DUK_DDD(DUK_DDDPRINT("built-in %ld, function-valued property %ld, key %!O, natidx %ld, length %ld, nargs %ld",
54018 (long) i, (long) j, (duk_heaphdr *) h_key, (long) natidx, (long) c_length,
7c673cae
FG
54019 (c_nargs == DUK_VARARGS ? (long) -1 : (long) c_nargs)));
54020
54021 /* Cast converts magic to 16-bit signed value */
54022 magic = (duk_int16_t) duk_bd_decode_flagged(bd, DUK__MAGIC_BITS, 0);
54023
54024#if defined(DUK_USE_LIGHTFUNC_BUILTINS)
54025 lightfunc_eligible =
54026 ((c_nargs >= DUK_LFUNC_NARGS_MIN && c_nargs <= DUK_LFUNC_NARGS_MAX) || (c_nargs == DUK_VARARGS)) &&
54027 (c_length <= DUK_LFUNC_LENGTH_MAX) &&
54028 (magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX);
11fdf7f2
TL
54029
54030 if (h_key == DUK_HTHREAD_STRING_EVAL(thr) ||
54031 h_key == DUK_HTHREAD_STRING_YIELD(thr) ||
54032 h_key == DUK_HTHREAD_STRING_RESUME(thr) ||
54033 h_key == DUK_HTHREAD_STRING_REQUIRE(thr)) {
7c673cae
FG
54034 /* These functions have trouble working as lightfuncs.
54035 * Some of them have specific asserts and some may have
54036 * additional properties (e.g. 'require.id' may be written).
54037 */
11fdf7f2 54038 DUK_D(DUK_DPRINT("reject as lightfunc: key=%!O, i=%d, j=%d", (duk_heaphdr *) h_key, (int) i, (int) j));
7c673cae
FG
54039 lightfunc_eligible = 0;
54040 }
54041
54042 if (lightfunc_eligible) {
54043 duk_tval tv_lfunc;
54044 duk_small_uint_t lf_nargs = (c_nargs == DUK_VARARGS ? DUK_LFUNC_NARGS_VARARGS : c_nargs);
54045 duk_small_uint_t lf_flags = DUK_LFUNC_FLAGS_PACK(magic, c_length, lf_nargs);
54046 DUK_TVAL_SET_LIGHTFUNC(&tv_lfunc, c_func, lf_flags);
54047 duk_push_tval(ctx, &tv_lfunc);
54048 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)));
54049 goto lightfunc_skip;
54050 }
54051
54052 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));
54053#endif /* DUK_USE_LIGHTFUNC_BUILTINS */
54054
11fdf7f2 54055 /* [ (builtin objects) name ] */
7c673cae
FG
54056
54057 duk_push_c_function_noconstruct_noexotic(ctx, c_func, c_nargs);
54058 h_func = duk_require_hnativefunction(ctx, -1);
54059 DUK_UNREF(h_func);
54060
54061 /* Currently all built-in native functions are strict.
54062 * This doesn't matter for many functions, but e.g.
54063 * String.prototype.charAt (and other string functions)
54064 * rely on being strict so that their 'this' binding is
54065 * not automatically coerced.
54066 */
54067 DUK_HOBJECT_SET_STRICT((duk_hobject *) h_func);
54068
54069 /* No built-in functions are constructable except the top
54070 * level ones (Number, etc).
54071 */
54072 DUK_ASSERT(!DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) h_func));
54073
54074 /* XXX: any way to avoid decoding magic bit; there are quite
54075 * many function properties and relatively few with magic values.
54076 */
54077 h_func->magic = magic;
54078
11fdf7f2 54079 /* [ (builtin objects) name func ] */
7c673cae
FG
54080
54081 duk_push_int(ctx, c_length);
54082 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
54083
11fdf7f2 54084 duk_dup(ctx, -2);
7c673cae
FG
54085 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
54086
54087 /* XXX: other properties of function instances; 'arguments', 'caller'. */
54088
54089 DUK_DD(DUK_DDPRINT("built-in object %ld, function property %ld -> %!T",
54090 (long) i, (long) j, (duk_tval *) duk_get_tval(ctx, -1)));
54091
11fdf7f2 54092 /* [ (builtin objects) name func ] */
7c673cae
FG
54093
54094 /*
54095 * The default property attributes are correct for all
54096 * function valued properties of built-in objects now.
54097 */
54098
54099#if defined(DUK_USE_LIGHTFUNC_BUILTINS)
54100 lightfunc_skip:
54101#endif
54102
11fdf7f2 54103 duk_xdef_prop(ctx, i, DUK_PROPDESC_FLAGS_WC);
7c673cae
FG
54104
54105 /* [ (builtin objects) ] */
54106 }
54107 }
54108
54109 /*
54110 * Special post-tweaks, for cases not covered by the init data format.
54111 *
54112 * - Set Date.prototype.toGMTString to Date.prototype.toUTCString.
54113 * toGMTString is required to have the same Function object as
54114 * toUTCString in E5 Section B.2.6. Note that while Smjs respects
54115 * this, V8 does not (the Function objects are distinct).
54116 *
54117 * - Make DoubleError non-extensible.
54118 *
54119 * - Add info about most important effective compile options to Duktape.
54120 *
54121 * - Possibly remove some properties (values or methods) which are not
54122 * desirable with current feature options but are not currently
54123 * conditional in init data.
54124 */
54125
54126 duk_get_prop_stridx(ctx, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_UTC_STRING);
54127 duk_xdef_prop_stridx(ctx, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_GMT_STRING, DUK_PROPDESC_FLAGS_WC);
54128
54129 h = duk_require_hobject(ctx, DUK_BIDX_DOUBLE_ERROR);
54130 DUK_ASSERT(h != NULL);
54131 DUK_HOBJECT_CLEAR_EXTENSIBLE(h);
54132
54133#if !defined(DUK_USE_ES6_OBJECT_PROTO_PROPERTY)
54134 DUK_DD(DUK_DDPRINT("delete Object.prototype.__proto__ built-in which is not enabled in features"));
54135 (void) duk_hobject_delprop_raw(thr, thr->builtins[DUK_BIDX_OBJECT_PROTOTYPE], DUK_HTHREAD_STRING___PROTO__(thr), DUK_DELPROP_FLAG_THROW);
54136#endif
54137
54138#if !defined(DUK_USE_ES6_OBJECT_SETPROTOTYPEOF)
54139 DUK_DD(DUK_DDPRINT("delete Object.setPrototypeOf built-in which is not enabled in features"));
54140 (void) duk_hobject_delprop_raw(thr, thr->builtins[DUK_BIDX_OBJECT_CONSTRUCTOR], DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr), DUK_DELPROP_FLAG_THROW);
54141#endif
54142
11fdf7f2 54143 /* XXX: relocate */
7c673cae
FG
54144 duk_push_string(ctx,
54145 /* Endianness indicator */
54146#if defined(DUK_USE_INTEGER_LE)
54147 "l"
54148#elif defined(DUK_USE_INTEGER_BE)
54149 "b"
54150#elif defined(DUK_USE_INTEGER_ME) /* integer mixed endian not really used now */
54151 "m"
54152#else
54153 "?"
54154#endif
54155#if defined(DUK_USE_DOUBLE_LE)
54156 "l"
54157#elif defined(DUK_USE_DOUBLE_BE)
54158 "b"
54159#elif defined(DUK_USE_DOUBLE_ME)
54160 "m"
54161#else
54162 "?"
7c673cae
FG
54163#endif
54164 " "
54165 /* Packed or unpacked tval */
54166#if defined(DUK_USE_PACKED_TVAL)
54167 "p"
54168#else
54169 "u"
54170#endif
54171#if defined(DUK_USE_FASTINT)
54172 "f"
54173#endif
54174 " "
54175 /* Low memory options */
54176#if defined(DUK_USE_STRTAB_CHAIN)
54177 "c" /* chain */
54178#elif defined(DUK_USE_STRTAB_PROBE)
54179 "p" /* probe */
54180#else
54181 "?"
54182#endif
54183#if !defined(DUK_USE_HEAPPTR16) && !defined(DUK_DATAPTR16) && !defined(DUK_FUNCPTR16)
54184 "n"
54185#endif
54186#if defined(DUK_USE_HEAPPTR16)
54187 "h"
54188#endif
54189#if defined(DUK_USE_DATAPTR16)
54190 "d"
54191#endif
54192#if defined(DUK_USE_FUNCPTR16)
54193 "f"
54194#endif
54195#if defined(DUK_USE_REFCOUNT16)
54196 "R"
54197#endif
54198#if defined(DUK_USE_STRHASH16)
54199 "H"
54200#endif
54201#if defined(DUK_USE_STRLEN16)
54202 "S"
54203#endif
54204#if defined(DUK_USE_BUFLEN16)
54205 "B"
54206#endif
54207#if defined(DUK_USE_OBJSIZES16)
54208 "O"
54209#endif
54210#if defined(DUK_USE_LIGHTFUNC_BUILTINS)
54211 "L"
11fdf7f2
TL
54212#endif
54213#if defined(DUK_USE_ROM_STRINGS) || defined(DUK_USE_ROM_OBJECTS)
54214 /* XXX: This won't be shown in practice now
54215 * because this code is not run when builtins
54216 * are in ROM.
54217 */
54218 "Z"
7c673cae
FG
54219#endif
54220 " "
54221 /* Object property allocation layout */
54222#if defined(DUK_USE_HOBJECT_LAYOUT_1)
54223 "p1"
54224#elif defined(DUK_USE_HOBJECT_LAYOUT_2)
54225 "p2"
54226#elif defined(DUK_USE_HOBJECT_LAYOUT_3)
54227 "p3"
54228#else
54229 "p?"
54230#endif
54231 " "
54232 /* Alignment guarantee */
54233#if (DUK_USE_ALIGN_BY == 4)
54234 "a4"
54235#elif (DUK_USE_ALIGN_BY == 8)
54236 "a8"
54237#elif (DUK_USE_ALIGN_BY == 1)
54238 "a1"
54239#else
54240#error invalid DUK_USE_ALIGN_BY
54241#endif
54242 " "
54243 /* Architecture, OS, and compiler strings */
54244 DUK_USE_ARCH_STRING
54245 " "
54246 DUK_USE_OS_STRING
54247 " "
54248 DUK_USE_COMPILER_STRING);
54249 duk_xdef_prop_stridx(ctx, DUK_BIDX_DUKTAPE, DUK_STRIDX_ENV, DUK_PROPDESC_FLAGS_WC);
54250
54251 /*
54252 * InitJS code - Ecmascript code evaluated from a built-in source
54253 * which provides e.g. backward compatibility. User can also provide
54254 * JS code to be evaluated at startup.
54255 */
54256
54257#ifdef DUK_USE_BUILTIN_INITJS
54258 /* XXX: compression */
54259 DUK_DD(DUK_DDPRINT("running built-in initjs"));
54260 duk_eval_string(ctx, (const char *) duk_initjs_data); /* initjs data is NUL terminated */
54261 duk_pop(ctx);
54262#endif /* DUK_USE_BUILTIN_INITJS */
54263
54264#ifdef DUK_USE_USER_INITJS
54265 /* XXX: compression (as an option) */
54266 DUK_DD(DUK_DDPRINT("running user initjs"));
54267 duk_eval_string_noresult(ctx, (const char *) DUK_USE_USER_INITJS);
54268#endif /* DUK_USE_USER_INITJS */
54269
54270 /*
54271 * Since built-ins are not often extended, compact them.
54272 */
54273
54274 DUK_DD(DUK_DDPRINT("compact built-ins"));
11fdf7f2
TL
54275 for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
54276 duk_hobject_compact_props(thr, duk_require_hobject(ctx, i));
7c673cae
FG
54277 }
54278
54279 DUK_D(DUK_DPRINT("INITBUILTINS END"));
54280
54281#ifdef DUK_USE_DDPRINT
11fdf7f2 54282 for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
7c673cae 54283 DUK_DD(DUK_DDPRINT("built-in object %ld after initialization and compacting: %!@iO",
11fdf7f2 54284 (long) i, (duk_heaphdr *) duk_require_hobject(ctx, i)));
7c673cae
FG
54285 }
54286#endif
54287
54288 /*
54289 * Pop built-ins from stack: they are now INCREF'd and
11fdf7f2
TL
54290 * reachable from the builtins[] array or indirectly
54291 * through builtins[].
7c673cae
FG
54292 */
54293
11fdf7f2 54294 duk_set_top(ctx, 0);
7c673cae
FG
54295 DUK_ASSERT_TOP(ctx, 0);
54296}
11fdf7f2 54297#endif /* DUK_USE_ROM_OBJECTS */
7c673cae
FG
54298
54299DUK_INTERNAL void duk_hthread_copy_builtin_objects(duk_hthread *thr_from, duk_hthread *thr_to) {
54300 duk_small_uint_t i;
54301
54302 for (i = 0; i < DUK_NUM_BUILTINS; i++) {
54303 thr_to->builtins[i] = thr_from->builtins[i];
54304 DUK_HOBJECT_INCREF_ALLOWNULL(thr_to, thr_to->builtins[i]); /* side effect free */
54305 }
54306}
7c673cae
FG
54307/*
54308 * Thread support.
54309 */
54310
54311/* include removed: duk_internal.h */
54312
54313DUK_INTERNAL void duk_hthread_terminate(duk_hthread *thr) {
54314 DUK_ASSERT(thr != NULL);
54315
54316 /* Order of unwinding is important */
54317
54318 duk_hthread_catchstack_unwind(thr, 0);
54319
54320 duk_hthread_callstack_unwind(thr, 0); /* side effects, possibly errors */
54321
54322 thr->valstack_bottom = thr->valstack;
54323 duk_set_top((duk_context *) thr, 0); /* unwinds valstack, updating refcounts */
54324
54325 thr->state = DUK_HTHREAD_STATE_TERMINATED;
54326
54327 /* Here we could remove references to built-ins, but it may not be
54328 * worth the effort because built-ins are quite likely to be shared
54329 * with another (unterminated) thread, and terminated threads are also
54330 * usually garbage collected quite quickly. Also, doing DECREFs
54331 * could trigger finalization, which would run on the current thread
54332 * and have access to only some of the built-ins. Garbage collection
54333 * deals with this correctly already.
54334 */
54335
54336 /* XXX: Shrink the stacks to minimize memory usage? May not
54337 * be worth the effort because terminated threads are usually
54338 * garbage collected quite soon.
54339 */
54340}
54341
54342DUK_INTERNAL duk_activation *duk_hthread_get_current_activation(duk_hthread *thr) {
54343 DUK_ASSERT(thr != NULL);
54344
54345 if (thr->callstack_top > 0) {
54346 return thr->callstack + thr->callstack_top - 1;
54347 } else {
54348 return NULL;
54349 }
54350}
54351
54352#if defined(DUK_USE_DEBUGGER_SUPPORT)
54353DUK_INTERNAL duk_uint_fast32_t duk_hthread_get_act_curr_pc(duk_hthread *thr, duk_activation *act) {
54354 duk_instr_t *bcode;
54355
54356 DUK_ASSERT(thr != NULL);
54357 DUK_ASSERT(act != NULL);
54358 DUK_UNREF(thr);
54359
54360 /* XXX: store 'bcode' pointer to activation for faster lookup? */
54361 if (act->func && DUK_HOBJECT_IS_COMPILEDFUNCTION(act->func)) {
54362 bcode = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, (duk_hcompiledfunction *) (act->func));
54363 return (duk_uint_fast32_t) (act->curr_pc - bcode);
54364 }
54365 return 0;
54366}
54367#endif /* DUK_USE_DEBUGGER_SUPPORT */
54368
54369DUK_INTERNAL duk_uint_fast32_t duk_hthread_get_act_prev_pc(duk_hthread *thr, duk_activation *act) {
54370 duk_instr_t *bcode;
54371 duk_uint_fast32_t ret;
54372
54373 DUK_ASSERT(thr != NULL);
54374 DUK_ASSERT(act != NULL);
54375 DUK_UNREF(thr);
54376
54377 if (act->func && DUK_HOBJECT_IS_COMPILEDFUNCTION(act->func)) {
54378 bcode = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, (duk_hcompiledfunction *) (act->func));
54379 ret = (duk_uint_fast32_t) (act->curr_pc - bcode);
54380 if (ret > 0) {
54381 ret--;
54382 }
54383 return ret;
54384 }
54385 return 0;
54386}
54387
54388/* Write bytecode executor's curr_pc back to topmost activation (if any). */
54389DUK_INTERNAL void duk_hthread_sync_currpc(duk_hthread *thr) {
54390 duk_activation *act;
54391
54392 DUK_ASSERT(thr != NULL);
54393
54394 if (thr->ptr_curr_pc != NULL) {
54395 /* ptr_curr_pc != NULL only when bytecode executor is active. */
54396 DUK_ASSERT(thr->callstack_top > 0);
54397 act = thr->callstack + thr->callstack_top - 1;
54398 act->curr_pc = *thr->ptr_curr_pc;
54399 }
54400}
54401
54402DUK_INTERNAL void duk_hthread_sync_and_null_currpc(duk_hthread *thr) {
54403 duk_activation *act;
54404
54405 DUK_ASSERT(thr != NULL);
54406
54407 if (thr->ptr_curr_pc != NULL) {
54408 /* ptr_curr_pc != NULL only when bytecode executor is active. */
54409 DUK_ASSERT(thr->callstack_top > 0);
54410 act = thr->callstack + thr->callstack_top - 1;
54411 act->curr_pc = *thr->ptr_curr_pc;
54412 thr->ptr_curr_pc = NULL;
54413 }
54414}
7c673cae
FG
54415/*
54416 * Manipulation of thread stacks (valstack, callstack, catchstack).
54417 *
54418 * Ideally unwinding of stacks should have no side effects, which would
54419 * then favor separate unwinding and shrink check primitives for each
54420 * stack type. A shrink check may realloc and thus have side effects.
54421 *
54422 * However, currently callstack unwinding itself has side effects, as it
54423 * needs to DECREF multiple objects, close environment records, etc.
54424 * Stacks must thus be unwound in the correct order by the caller.
54425 *
54426 * (XXX: This should be probably reworked so that there is a shared
54427 * unwind primitive which handles all stacks as requested, and knows
54428 * the proper order for unwinding.)
54429 *
54430 * Valstack entries above 'top' are always kept initialized to
54431 * "undefined unused". Callstack and catchstack entries above 'top'
54432 * are not zeroed and are left as garbage.
54433 *
54434 * Value stack handling is mostly a part of the API implementation.
54435 */
54436
54437/* include removed: duk_internal.h */
54438
54439/* check that there is space for at least one new entry */
54440DUK_INTERNAL void duk_hthread_callstack_grow(duk_hthread *thr) {
54441 duk_activation *new_ptr;
54442 duk_size_t old_size;
54443 duk_size_t new_size;
54444
54445 DUK_ASSERT(thr != NULL);
54446 DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */
54447 DUK_ASSERT(thr->callstack_size >= thr->callstack_top);
54448
54449 if (thr->callstack_top < thr->callstack_size) {
54450 return;
54451 }
54452
54453 old_size = thr->callstack_size;
54454 new_size = old_size + DUK_CALLSTACK_GROW_STEP;
54455
54456 /* this is a bit approximate (errors out before max is reached); this is OK */
54457 if (new_size >= thr->callstack_max) {
11fdf7f2 54458 DUK_ERROR_RANGE(thr, DUK_STR_CALLSTACK_LIMIT);
7c673cae
FG
54459 }
54460
54461 DUK_DD(DUK_DDPRINT("growing callstack %ld -> %ld", (long) old_size, (long) new_size));
54462
54463 /*
54464 * Note: must use indirect variant of DUK_REALLOC() because underlying
54465 * pointer may be changed by mark-and-sweep.
54466 */
54467
54468 DUK_ASSERT(new_size > 0);
54469 new_ptr = (duk_activation *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_callstack_ptr, (void *) thr, sizeof(duk_activation) * new_size);
54470 if (!new_ptr) {
54471 /* No need for a NULL/zero-size check because new_size > 0) */
11fdf7f2 54472 DUK_ERROR_ALLOC_DEFMSG(thr);
7c673cae
FG
54473 }
54474 thr->callstack = new_ptr;
54475 thr->callstack_size = new_size;
54476
54477 /* note: any entries above the callstack top are garbage and not zeroed */
54478}
54479
54480DUK_INTERNAL void duk_hthread_callstack_shrink_check(duk_hthread *thr) {
54481 duk_size_t new_size;
54482 duk_activation *p;
54483
54484 DUK_ASSERT(thr != NULL);
54485 DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */
54486 DUK_ASSERT(thr->callstack_size >= thr->callstack_top);
54487
54488 if (thr->callstack_size - thr->callstack_top < DUK_CALLSTACK_SHRINK_THRESHOLD) {
54489 return;
54490 }
54491
54492 new_size = thr->callstack_top + DUK_CALLSTACK_SHRINK_SPARE;
54493 DUK_ASSERT(new_size >= thr->callstack_top);
54494
54495 DUK_DD(DUK_DDPRINT("shrinking callstack %ld -> %ld", (long) thr->callstack_size, (long) new_size));
54496
54497 /*
54498 * Note: must use indirect variant of DUK_REALLOC() because underlying
54499 * pointer may be changed by mark-and-sweep.
54500 */
54501
54502 /* shrink failure is not fatal */
54503 p = (duk_activation *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_callstack_ptr, (void *) thr, sizeof(duk_activation) * new_size);
54504 if (p) {
54505 thr->callstack = p;
54506 thr->callstack_size = new_size;
54507 } else {
54508 /* Because new_size != 0, if condition doesn't need to be
54509 * (p != NULL || new_size == 0).
54510 */
54511 DUK_ASSERT(new_size != 0);
54512 DUK_D(DUK_DPRINT("callstack shrink failed, ignoring"));
54513 }
54514
54515 /* note: any entries above the callstack top are garbage and not zeroed */
54516}
54517
54518DUK_INTERNAL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_top) {
54519 duk_size_t idx;
54520
54521 DUK_DDD(DUK_DDDPRINT("unwind callstack top of thread %p from %ld to %ld",
54522 (void *) thr,
54523 (thr != NULL ? (long) thr->callstack_top : (long) -1),
54524 (long) new_top));
54525
54526 DUK_ASSERT(thr);
54527 DUK_ASSERT(thr->heap);
54528 DUK_ASSERT_DISABLE(new_top >= 0); /* unsigned */
54529 DUK_ASSERT((duk_size_t) new_top <= thr->callstack_top); /* cannot grow */
54530
54531 /*
54532 * The loop below must avoid issues with potential callstack
54533 * reallocations. A resize (and other side effects) may happen
54534 * e.g. due to finalizer/errhandler calls caused by a refzero or
54535 * mark-and-sweep. Arbitrary finalizers may run, because when
54536 * an environment record is refzero'd, it may refer to arbitrary
54537 * values which also become refzero'd.
54538 *
54539 * So, the pointer 'p' is re-looked-up below whenever a side effect
54540 * might have changed it.
54541 */
54542
54543 idx = thr->callstack_top;
54544 while (idx > new_top) {
54545 duk_activation *act;
54546 duk_hobject *func;
54547#ifdef DUK_USE_REFERENCE_COUNTING
54548 duk_hobject *tmp;
54549#endif
54550#ifdef DUK_USE_DEBUGGER_SUPPORT
54551 duk_heap *heap;
54552#endif
54553
54554 idx--;
54555 DUK_ASSERT_DISABLE(idx >= 0); /* unsigned */
54556 DUK_ASSERT((duk_size_t) idx < thr->callstack_size); /* true, despite side effect resizes */
54557
54558 act = thr->callstack + idx;
54559 /* With lightfuncs, act 'func' may be NULL */
54560
54561#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
54562 /*
54563 * Restore 'caller' property for non-strict callee functions.
54564 */
54565
54566 func = DUK_ACT_GET_FUNC(act);
54567 if (func != NULL && !DUK_HOBJECT_HAS_STRICT(func)) {
54568 duk_tval *tv_caller;
54569 duk_tval tv_tmp;
54570 duk_hobject *h_tmp;
54571
54572 tv_caller = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_CALLER(thr));
54573
54574 /* The act->prev_caller should only be set if the entry for 'caller'
54575 * exists (as it is only set in that case, and the property is not
54576 * configurable), but handle all the cases anyway.
54577 */
54578
54579 if (tv_caller) {
54580 DUK_TVAL_SET_TVAL(&tv_tmp, tv_caller);
54581 if (act->prev_caller) {
54582 /* Just transfer the refcount from act->prev_caller to tv_caller,
54583 * so no need for a refcount update. This is the expected case.
54584 */
54585 DUK_TVAL_SET_OBJECT(tv_caller, act->prev_caller);
54586 act->prev_caller = NULL;
54587 } else {
54588 DUK_TVAL_SET_NULL(tv_caller); /* no incref needed */
54589 DUK_ASSERT(act->prev_caller == NULL);
54590 }
54591 DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
54592 } else {
54593 h_tmp = act->prev_caller;
54594 if (h_tmp) {
54595 act->prev_caller = NULL;
54596 DUK_HOBJECT_DECREF(thr, h_tmp); /* side effects */
54597 }
54598 }
54599 act = thr->callstack + idx; /* avoid side effects */
54600 DUK_ASSERT(act->prev_caller == NULL);
54601 }
54602#endif
54603
54604 /*
54605 * Unwind debugger state. If we unwind while stepping
54606 * (either step over or step into), pause execution.
54607 */
54608
54609#if defined(DUK_USE_DEBUGGER_SUPPORT)
54610 heap = thr->heap;
54611 if (heap->dbg_step_thread == thr &&
54612 heap->dbg_step_csindex == idx) {
54613 /* Pause for all step types: step into, step over, step out.
54614 * This is the only place explicitly handling a step out.
54615 */
54616 DUK_HEAP_SET_PAUSED(heap);
54617 DUK_ASSERT(heap->dbg_step_thread == NULL);
54618 }
54619#endif
54620
54621 /*
54622 * Close environment record(s) if they exist.
54623 *
54624 * Only variable environments are closed. If lex_env != var_env, it
54625 * cannot currently contain any register bound declarations.
54626 *
54627 * Only environments created for a NEWENV function are closed. If an
54628 * environment is created for e.g. an eval call, it must not be closed.
54629 */
54630
54631 func = DUK_ACT_GET_FUNC(act);
54632 if (func != NULL && !DUK_HOBJECT_HAS_NEWENV(func)) {
54633 DUK_DDD(DUK_DDDPRINT("skip closing environments, envs not owned by this activation"));
54634 goto skip_env_close;
54635 }
54636 /* func is NULL for lightfunc */
54637
54638 DUK_ASSERT(act->lex_env == act->var_env);
54639 if (act->var_env != NULL) {
54640 DUK_DDD(DUK_DDDPRINT("closing var_env record %p -> %!O",
54641 (void *) act->var_env, (duk_heaphdr *) act->var_env));
54642 duk_js_close_environment_record(thr, act->var_env, func, act->idx_bottom);
54643 act = thr->callstack + idx; /* avoid side effect issues */
54644 }
54645
54646#if 0
54647 if (act->lex_env != NULL) {
54648 if (act->lex_env == act->var_env) {
54649 /* common case, already closed, so skip */
54650 DUK_DD(DUK_DDPRINT("lex_env and var_env are the same and lex_env "
54651 "already closed -> skip closing lex_env"));
54652 ;
54653 } else {
54654 DUK_DD(DUK_DDPRINT("closing lex_env record %p -> %!O",
54655 (void *) act->lex_env, (duk_heaphdr *) act->lex_env));
54656 duk_js_close_environment_record(thr, act->lex_env, DUK_ACT_GET_FUNC(act), act->idx_bottom);
54657 act = thr->callstack + idx; /* avoid side effect issues */
54658 }
54659 }
54660#endif
54661
54662 DUK_ASSERT((act->lex_env == NULL) ||
54663 ((duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL) &&
54664 (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_VARMAP(thr)) == NULL) &&
54665 (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL) &&
54666 (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL)));
54667
54668 DUK_ASSERT((act->var_env == NULL) ||
54669 ((duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL) &&
54670 (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_VARMAP(thr)) == NULL) &&
54671 (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL) &&
54672 (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL)));
54673
54674 skip_env_close:
54675
54676 /*
54677 * Update preventcount
54678 */
54679
54680 if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
54681 DUK_ASSERT(thr->callstack_preventcount >= 1);
54682 thr->callstack_preventcount--;
54683 }
54684
54685 /*
54686 * Reference count updates
54687 *
54688 * Note: careful manipulation of refcounts. The top is
54689 * not updated yet, so all the activations are reachable
54690 * for mark-and-sweep (which may be triggered by decref).
54691 * However, the pointers are NULL so this is not an issue.
54692 */
54693
54694#ifdef DUK_USE_REFERENCE_COUNTING
54695 tmp = act->var_env;
54696#endif
54697 act->var_env = NULL;
54698#ifdef DUK_USE_REFERENCE_COUNTING
54699 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
54700 act = thr->callstack + idx; /* avoid side effect issues */
54701#endif
54702
54703#ifdef DUK_USE_REFERENCE_COUNTING
54704 tmp = act->lex_env;
54705#endif
54706 act->lex_env = NULL;
54707#ifdef DUK_USE_REFERENCE_COUNTING
54708 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
54709 act = thr->callstack + idx; /* avoid side effect issues */
54710#endif
54711
54712 /* Note: this may cause a corner case situation where a finalizer
54713 * may see a currently reachable activation whose 'func' is NULL.
54714 */
54715#ifdef DUK_USE_REFERENCE_COUNTING
54716 tmp = DUK_ACT_GET_FUNC(act);
54717#endif
54718 act->func = NULL;
54719#ifdef DUK_USE_REFERENCE_COUNTING
54720 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
54721 act = thr->callstack + idx; /* avoid side effect issues */
54722 DUK_UNREF(act);
54723#endif
54724 }
54725
54726 thr->callstack_top = new_top;
54727
54728 /*
54729 * We could clear the book-keeping variables for the topmost activation,
54730 * but don't do so now.
54731 */
54732#if 0
54733 if (thr->callstack_top > 0) {
54734 duk_activation *act = thr->callstack + thr->callstack_top - 1;
54735 act->idx_retval = 0;
54736 }
54737#endif
54738
54739 /* Note: any entries above the callstack top are garbage and not zeroed.
54740 * Also topmost activation idx_retval is garbage (not zeroed), and must
54741 * be ignored.
54742 */
54743}
54744
54745DUK_INTERNAL void duk_hthread_catchstack_grow(duk_hthread *thr) {
54746 duk_catcher *new_ptr;
54747 duk_size_t old_size;
54748 duk_size_t new_size;
54749
54750 DUK_ASSERT(thr != NULL);
54751 DUK_ASSERT_DISABLE(thr->catchstack_top); /* avoid warning (unsigned) */
54752 DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top);
54753
54754 if (thr->catchstack_top < thr->catchstack_size) {
54755 return;
54756 }
54757
54758 old_size = thr->catchstack_size;
54759 new_size = old_size + DUK_CATCHSTACK_GROW_STEP;
54760
54761 /* this is a bit approximate (errors out before max is reached); this is OK */
54762 if (new_size >= thr->catchstack_max) {
11fdf7f2 54763 DUK_ERROR_RANGE(thr, DUK_STR_CATCHSTACK_LIMIT);
7c673cae
FG
54764 }
54765
54766 DUK_DD(DUK_DDPRINT("growing catchstack %ld -> %ld", (long) old_size, (long) new_size));
54767
54768 /*
54769 * Note: must use indirect variant of DUK_REALLOC() because underlying
54770 * pointer may be changed by mark-and-sweep.
54771 */
54772
54773 DUK_ASSERT(new_size > 0);
54774 new_ptr = (duk_catcher *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_catchstack_ptr, (void *) thr, sizeof(duk_catcher) * new_size);
54775 if (!new_ptr) {
54776 /* No need for a NULL/zero-size check because new_size > 0) */
11fdf7f2 54777 DUK_ERROR_ALLOC_DEFMSG(thr);
7c673cae
FG
54778 }
54779 thr->catchstack = new_ptr;
54780 thr->catchstack_size = new_size;
54781
54782 /* note: any entries above the catchstack top are garbage and not zeroed */
54783}
54784
54785DUK_INTERNAL void duk_hthread_catchstack_shrink_check(duk_hthread *thr) {
54786 duk_size_t new_size;
54787 duk_catcher *p;
54788
54789 DUK_ASSERT(thr != NULL);
54790 DUK_ASSERT_DISABLE(thr->catchstack_top >= 0); /* avoid warning (unsigned) */
54791 DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top);
54792
54793 if (thr->catchstack_size - thr->catchstack_top < DUK_CATCHSTACK_SHRINK_THRESHOLD) {
54794 return;
54795 }
54796
54797 new_size = thr->catchstack_top + DUK_CATCHSTACK_SHRINK_SPARE;
54798 DUK_ASSERT(new_size >= thr->catchstack_top);
54799
54800 DUK_DD(DUK_DDPRINT("shrinking catchstack %ld -> %ld", (long) thr->catchstack_size, (long) new_size));
54801
54802 /*
54803 * Note: must use indirect variant of DUK_REALLOC() because underlying
54804 * pointer may be changed by mark-and-sweep.
54805 */
54806
54807 /* shrink failure is not fatal */
54808 p = (duk_catcher *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_catchstack_ptr, (void *) thr, sizeof(duk_catcher) * new_size);
54809 if (p) {
54810 thr->catchstack = p;
54811 thr->catchstack_size = new_size;
54812 } else {
54813 /* Because new_size != 0, if condition doesn't need to be
54814 * (p != NULL || new_size == 0).
54815 */
54816 DUK_ASSERT(new_size != 0);
54817 DUK_D(DUK_DPRINT("catchstack shrink failed, ignoring"));
54818 }
54819
54820 /* note: any entries above the catchstack top are garbage and not zeroed */
54821}
54822
54823DUK_INTERNAL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new_top) {
54824 duk_size_t idx;
54825
54826 DUK_DDD(DUK_DDDPRINT("unwind catchstack top of thread %p from %ld to %ld",
54827 (void *) thr,
54828 (thr != NULL ? (long) thr->catchstack_top : (long) -1),
54829 (long) new_top));
54830
54831 DUK_ASSERT(thr);
54832 DUK_ASSERT(thr->heap);
54833 DUK_ASSERT_DISABLE(new_top >= 0); /* unsigned */
54834 DUK_ASSERT((duk_size_t) new_top <= thr->catchstack_top); /* cannot grow */
54835
54836 /*
54837 * Since there are no references in the catcher structure,
54838 * unwinding is quite simple. The only thing we need to
54839 * look out for is popping a possible lexical environment
54840 * established for an active catch clause.
54841 */
54842
54843 idx = thr->catchstack_top;
54844 while (idx > new_top) {
54845 duk_catcher *p;
54846 duk_activation *act;
54847 duk_hobject *env;
54848
54849 idx--;
54850 DUK_ASSERT_DISABLE(idx >= 0); /* unsigned */
54851 DUK_ASSERT((duk_size_t) idx < thr->catchstack_size);
54852
54853 p = thr->catchstack + idx;
54854
54855 if (DUK_CAT_HAS_LEXENV_ACTIVE(p)) {
54856 DUK_DDD(DUK_DDDPRINT("unwinding catchstack idx %ld, callstack idx %ld, callstack top %ld: lexical environment active",
54857 (long) idx, (long) p->callstack_index, (long) thr->callstack_top));
54858
54859 /* XXX: Here we have a nasty dependency: the need to manipulate
54860 * the callstack means that catchstack must always be unwound by
54861 * the caller before unwinding the callstack. This should be fixed
54862 * later.
54863 */
54864
54865 /* Note that multiple catchstack entries may refer to the same
54866 * callstack entry.
54867 */
54868 act = thr->callstack + p->callstack_index;
54869 DUK_ASSERT(act >= thr->callstack);
54870 DUK_ASSERT(act < thr->callstack + thr->callstack_top);
54871
54872 DUK_DDD(DUK_DDDPRINT("catchstack_index=%ld, callstack_index=%ld, lex_env=%!iO",
54873 (long) idx, (long) p->callstack_index,
54874 (duk_heaphdr *) act->lex_env));
54875
54876 env = act->lex_env; /* current lex_env of the activation (created for catcher) */
54877 DUK_ASSERT(env != NULL); /* must be, since env was created when catcher was created */
54878 act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env); /* prototype is lex_env before catcher created */
54879 DUK_HOBJECT_DECREF(thr, env);
54880
54881 /* There is no need to decref anything else than 'env': if 'env'
54882 * becomes unreachable, refzero will handle decref'ing its prototype.
54883 */
54884 }
54885 }
54886
54887 thr->catchstack_top = new_top;
54888
54889 /* note: any entries above the catchstack top are garbage and not zeroed */
54890}
7c673cae
FG
54891/*
54892 * Call handling.
54893 *
11fdf7f2
TL
54894 * Main functions are:
54895 *
54896 * - duk_handle_call_unprotected(): unprotected call to Ecmascript or
54897 * Duktape/C function
54898 * - duk_handle_call_protected(): protected call to Ecmascript or
54899 * Duktape/C function
54900 * - duk_handle_safe_call(): make a protected C call within current
54901 * activation
54902 * - duk_handle_ecma_call_setup(): Ecmascript-to-Ecmascript calls
54903 * (not always possible), including tail calls and coroutine resume
54904 *
54905 * See 'execution.rst'.
54906 *
54907 * Note: setjmp() and local variables have a nasty interaction,
54908 * see execution.rst; non-volatile locals modified after setjmp()
54909 * call are not guaranteed to keep their value.
7c673cae
FG
54910 */
54911
54912/* include removed: duk_internal.h */
54913
54914/*
11fdf7f2
TL
54915 * Forward declarations.
54916 */
54917
54918DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr,
54919 duk_idx_t num_stack_args,
54920 duk_small_uint_t call_flags,
54921 duk_idx_t idx_func);
54922DUK_LOCAL void duk__handle_call_error(duk_hthread *thr,
54923 duk_size_t entry_valstack_bottom_index,
54924 duk_size_t entry_valstack_end,
54925 duk_size_t entry_catchstack_top,
54926 duk_size_t entry_callstack_top,
54927 duk_int_t entry_call_recursion_depth,
54928 duk_hthread *entry_curr_thread,
54929 duk_uint_fast8_t entry_thread_state,
54930 duk_instr_t **entry_ptr_curr_pc,
54931 duk_idx_t idx_func,
54932 duk_jmpbuf *old_jmpbuf_ptr);
54933DUK_LOCAL void duk__handle_safe_call_inner(duk_hthread *thr,
54934 duk_safe_call_function func,
54935 duk_idx_t idx_retbase,
54936 duk_idx_t num_stack_rets,
54937 duk_size_t entry_valstack_bottom_index,
54938 duk_size_t entry_callstack_top,
54939 duk_size_t entry_catchstack_top);
54940DUK_LOCAL void duk__handle_safe_call_error(duk_hthread *thr,
54941 duk_idx_t idx_retbase,
54942 duk_idx_t num_stack_rets,
54943 duk_size_t entry_valstack_bottom_index,
54944 duk_size_t entry_callstack_top,
54945 duk_size_t entry_catchstack_top,
54946 duk_jmpbuf *old_jmpbuf_ptr);
54947DUK_LOCAL void duk__handle_safe_call_shared(duk_hthread *thr,
54948 duk_idx_t idx_retbase,
54949 duk_idx_t num_stack_rets,
54950 duk_int_t entry_call_recursion_depth,
54951 duk_hthread *entry_curr_thread,
54952 duk_uint_fast8_t entry_thread_state,
54953 duk_instr_t **entry_ptr_curr_pc);
54954
54955/*
54956 * Interrupt counter fixup (for development only).
7c673cae
FG
54957 */
54958
54959#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
54960DUK_LOCAL void duk__interrupt_fixup(duk_hthread *thr, duk_hthread *entry_curr_thread) {
11fdf7f2 54961 /* Currently the bytecode executor and executor interrupt
7c673cae
FG
54962 * instruction counts are off because we don't execute the
54963 * interrupt handler when we're about to exit from the initial
54964 * user call into Duktape.
54965 *
54966 * If we were to execute the interrupt handler here, the counts
54967 * would match. You can enable this block manually to check
54968 * that this is the case.
54969 */
54970
54971 DUK_ASSERT(thr != NULL);
54972 DUK_ASSERT(thr->heap != NULL);
54973
11fdf7f2 54974#if defined(DUK_USE_INTERRUPT_DEBUG_FIXUP)
7c673cae
FG
54975 if (entry_curr_thread == NULL) {
54976 thr->interrupt_init = thr->interrupt_init - thr->interrupt_counter;
54977 thr->heap->inst_count_interrupt += thr->interrupt_init;
54978 DUK_DD(DUK_DDPRINT("debug test: updated interrupt count on exit to "
54979 "user code, instruction counts: executor=%ld, interrupt=%ld",
54980 (long) thr->heap->inst_count_exec, (long) thr->heap->inst_count_interrupt));
54981 DUK_ASSERT(thr->heap->inst_count_exec == thr->heap->inst_count_interrupt);
54982 }
54983#else
54984 DUK_UNREF(thr);
54985 DUK_UNREF(entry_curr_thread);
54986#endif
54987}
54988#endif
54989
54990/*
54991 * Arguments object creation.
54992 *
11fdf7f2
TL
54993 * Creating arguments objects involves many small details, see E5 Section
54994 * 10.6 for the specific requirements. Much of the arguments object exotic
54995 * behavior is implemented in duk_hobject_props.c, and is enabled by the
54996 * object flag DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS.
7c673cae
FG
54997 */
54998
11fdf7f2
TL
54999DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
55000 duk_hobject *func,
55001 duk_hobject *varenv,
55002 duk_idx_t idx_argbase, /* idx of first argument on stack */
55003 duk_idx_t num_stack_args) { /* num args starting from idx_argbase */
7c673cae
FG
55004 duk_context *ctx = (duk_context *) thr;
55005 duk_hobject *arg; /* 'arguments' */
55006 duk_hobject *formals; /* formals for 'func' (may be NULL if func is a C function) */
55007 duk_idx_t i_arg;
55008 duk_idx_t i_map;
55009 duk_idx_t i_mappednames;
55010 duk_idx_t i_formals;
55011 duk_idx_t i_argbase;
55012 duk_idx_t n_formals;
55013 duk_idx_t idx;
55014 duk_bool_t need_map;
55015
55016 DUK_DDD(DUK_DDDPRINT("creating arguments object for func=%!iO, varenv=%!iO, "
55017 "idx_argbase=%ld, num_stack_args=%ld",
55018 (duk_heaphdr *) func, (duk_heaphdr *) varenv,
55019 (long) idx_argbase, (long) num_stack_args));
55020
55021 DUK_ASSERT(thr != NULL);
55022 DUK_ASSERT(func != NULL);
55023 DUK_ASSERT(DUK_HOBJECT_IS_NONBOUND_FUNCTION(func));
55024 DUK_ASSERT(varenv != NULL);
55025 DUK_ASSERT(idx_argbase >= 0); /* assumed to bottom relative */
55026 DUK_ASSERT(num_stack_args >= 0);
55027
55028 need_map = 0;
55029
55030 i_argbase = idx_argbase;
55031 DUK_ASSERT(i_argbase >= 0);
55032
55033 duk_push_hobject(ctx, func);
55034 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_FORMALS);
55035 formals = duk_get_hobject(ctx, -1);
55036 n_formals = 0;
55037 if (formals) {
55038 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LENGTH);
55039 n_formals = (duk_idx_t) duk_require_int(ctx, -1);
55040 duk_pop(ctx);
55041 }
55042 duk_remove(ctx, -2); /* leave formals on stack for later use */
55043 i_formals = duk_require_top_index(ctx);
55044
55045 DUK_ASSERT(n_formals >= 0);
55046 DUK_ASSERT(formals != NULL || n_formals == 0);
55047
55048 DUK_DDD(DUK_DDDPRINT("func=%!O, formals=%!O, n_formals=%ld",
55049 (duk_heaphdr *) func, (duk_heaphdr *) formals,
55050 (long) n_formals));
55051
55052 /* [ ... formals ] */
55053
55054 /*
55055 * Create required objects:
55056 * - 'arguments' object: array-like, but not an array
55057 * - 'map' object: internal object, tied to 'arguments'
55058 * - 'mappedNames' object: temporary value used during construction
55059 */
55060
55061 i_arg = duk_push_object_helper(ctx,
55062 DUK_HOBJECT_FLAG_EXTENSIBLE |
55063 DUK_HOBJECT_FLAG_ARRAY_PART |
55064 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARGUMENTS),
55065 DUK_BIDX_OBJECT_PROTOTYPE);
55066 DUK_ASSERT(i_arg >= 0);
55067 arg = duk_require_hobject(ctx, -1);
55068 DUK_ASSERT(arg != NULL);
55069
55070 i_map = duk_push_object_helper(ctx,
55071 DUK_HOBJECT_FLAG_EXTENSIBLE |
55072 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
55073 -1); /* no prototype */
55074 DUK_ASSERT(i_map >= 0);
55075
55076 i_mappednames = duk_push_object_helper(ctx,
55077 DUK_HOBJECT_FLAG_EXTENSIBLE |
55078 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
55079 -1); /* no prototype */
55080 DUK_ASSERT(i_mappednames >= 0);
55081
11fdf7f2 55082 /* [ ... formals arguments map mappedNames ] */
7c673cae
FG
55083
55084 DUK_DDD(DUK_DDDPRINT("created arguments related objects: "
55085 "arguments at index %ld -> %!O "
55086 "map at index %ld -> %!O "
55087 "mappednames at index %ld -> %!O",
55088 (long) i_arg, (duk_heaphdr *) duk_get_hobject(ctx, i_arg),
55089 (long) i_map, (duk_heaphdr *) duk_get_hobject(ctx, i_map),
55090 (long) i_mappednames, (duk_heaphdr *) duk_get_hobject(ctx, i_mappednames)));
55091
55092 /*
55093 * Init arguments properties, map, etc.
55094 */
55095
55096 duk_push_int(ctx, num_stack_args);
55097 duk_xdef_prop_stridx(ctx, i_arg, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_WC);
55098
55099 /*
55100 * Init argument related properties
55101 */
55102
55103 /* step 11 */
55104 idx = num_stack_args - 1;
55105 while (idx >= 0) {
55106 DUK_DDD(DUK_DDDPRINT("arg idx %ld, argbase=%ld, argidx=%ld",
55107 (long) idx, (long) i_argbase, (long) (i_argbase + idx)));
55108
55109 DUK_DDD(DUK_DDDPRINT("define arguments[%ld]=arg", (long) idx));
55110 duk_dup(ctx, i_argbase + idx);
55111 duk_xdef_prop_index_wec(ctx, i_arg, (duk_uarridx_t) idx);
55112 DUK_DDD(DUK_DDDPRINT("defined arguments[%ld]=arg", (long) idx));
55113
55114 /* step 11.c is relevant only if non-strict (checked in 11.c.ii) */
55115 if (!DUK_HOBJECT_HAS_STRICT(func) && idx < n_formals) {
55116 DUK_ASSERT(formals != NULL);
55117
55118 DUK_DDD(DUK_DDDPRINT("strict function, index within formals (%ld < %ld)",
55119 (long) idx, (long) n_formals));
55120
55121 duk_get_prop_index(ctx, i_formals, idx);
55122 DUK_ASSERT(duk_is_string(ctx, -1));
55123
11fdf7f2 55124 duk_dup(ctx, -1); /* [ ... name name ] */
7c673cae
FG
55125
55126 if (!duk_has_prop(ctx, i_mappednames)) {
55127 /* steps 11.c.ii.1 - 11.c.ii.4, but our internal book-keeping
55128 * differs from the reference model
55129 */
55130
11fdf7f2 55131 /* [ ... name ] */
7c673cae
FG
55132
55133 need_map = 1;
55134
55135 DUK_DDD(DUK_DDDPRINT("set mappednames[%s]=%ld",
55136 (const char *) duk_get_string(ctx, -1),
55137 (long) idx));
55138 duk_dup(ctx, -1); /* name */
55139 duk_push_uint(ctx, (duk_uint_t) idx); /* index */
55140 duk_to_string(ctx, -1);
55141 duk_xdef_prop_wec(ctx, i_mappednames); /* out of spec, must be configurable */
55142
55143 DUK_DDD(DUK_DDDPRINT("set map[%ld]=%s",
55144 (long) idx,
55145 duk_get_string(ctx, -1)));
55146 duk_dup(ctx, -1); /* name */
55147 duk_xdef_prop_index_wec(ctx, i_map, (duk_uarridx_t) idx); /* out of spec, must be configurable */
55148 } else {
55149 /* duk_has_prop() popped the second 'name' */
55150 }
55151
11fdf7f2 55152 /* [ ... name ] */
7c673cae
FG
55153 duk_pop(ctx); /* pop 'name' */
55154 }
55155
55156 idx--;
55157 }
55158
55159 DUK_DDD(DUK_DDDPRINT("actual arguments processed"));
55160
55161 /* step 12 */
55162 if (need_map) {
55163 DUK_DDD(DUK_DDDPRINT("adding 'map' and 'varenv' to arguments object"));
55164
55165 /* should never happen for a strict callee */
55166 DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(func));
55167
55168 duk_dup(ctx, i_map);
55169 duk_xdef_prop_stridx(ctx, i_arg, DUK_STRIDX_INT_MAP, DUK_PROPDESC_FLAGS_NONE); /* out of spec, don't care */
55170
55171 /* The variable environment for magic variable bindings needs to be
55172 * given by the caller and recorded in the arguments object.
55173 *
55174 * See E5 Section 10.6, the creation of setters/getters.
55175 *
55176 * The variable environment also provides access to the callee, so
55177 * an explicit (internal) callee property is not needed.
55178 */
55179
55180 duk_push_hobject(ctx, varenv);
55181 duk_xdef_prop_stridx(ctx, i_arg, DUK_STRIDX_INT_VARENV, DUK_PROPDESC_FLAGS_NONE); /* out of spec, don't care */
55182 }
55183
55184 /* steps 13-14 */
55185 if (DUK_HOBJECT_HAS_STRICT(func)) {
11fdf7f2
TL
55186 /* Callee/caller are throwers and are not deletable etc. They
55187 * could be implemented as virtual properties, but currently
55188 * there is no support for virtual properties which are accessors
55189 * (only plain virtual properties). This would not be difficult
55190 * to change in duk_hobject_props, but we can make the throwers
55191 * normal, concrete properties just as easily.
7c673cae 55192 *
11fdf7f2
TL
55193 * Note that the specification requires that the *same* thrower
55194 * built-in object is used here! See E5 Section 10.6 main
55195 * algoritm, step 14, and Section 13.2.3 which describes the
55196 * thrower. See test case test-arguments-throwers.js.
7c673cae
FG
55197 */
55198
55199 DUK_DDD(DUK_DDDPRINT("strict function, setting caller/callee to throwers"));
55200
55201 duk_xdef_prop_stridx_thrower(ctx, i_arg, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
55202 duk_xdef_prop_stridx_thrower(ctx, i_arg, DUK_STRIDX_CALLEE, DUK_PROPDESC_FLAGS_NONE);
55203 } else {
55204 DUK_DDD(DUK_DDDPRINT("non-strict function, setting callee to actual value"));
55205 duk_push_hobject(ctx, func);
55206 duk_xdef_prop_stridx(ctx, i_arg, DUK_STRIDX_CALLEE, DUK_PROPDESC_FLAGS_WC);
55207 }
55208
55209 /* set exotic behavior only after we're done */
55210 if (need_map) {
11fdf7f2
TL
55211 /* Exotic behaviors are only enabled for arguments objects
55212 * which have a parameter map (see E5 Section 10.6 main
55213 * algorithm, step 12).
7c673cae 55214 *
11fdf7f2
TL
55215 * In particular, a non-strict arguments object with no
55216 * mapped formals does *NOT* get exotic behavior, even
55217 * for e.g. "caller" property. This seems counterintuitive
55218 * but seems to be the case.
7c673cae
FG
55219 */
55220
55221 /* cannot be strict (never mapped variables) */
55222 DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(func));
55223
55224 DUK_DDD(DUK_DDDPRINT("enabling exotic behavior for arguments object"));
55225 DUK_HOBJECT_SET_EXOTIC_ARGUMENTS(arg);
55226 } else {
55227 DUK_DDD(DUK_DDDPRINT("not enabling exotic behavior for arguments object"));
55228 }
55229
7c673cae
FG
55230 DUK_DDD(DUK_DDDPRINT("final arguments related objects: "
55231 "arguments at index %ld -> %!O "
55232 "map at index %ld -> %!O "
55233 "mappednames at index %ld -> %!O",
55234 (long) i_arg, (duk_heaphdr *) duk_get_hobject(ctx, i_arg),
55235 (long) i_map, (duk_heaphdr *) duk_get_hobject(ctx, i_map),
55236 (long) i_mappednames, (duk_heaphdr *) duk_get_hobject(ctx, i_mappednames)));
55237
11fdf7f2
TL
55238 /* [ args(n) [crud] formals arguments map mappednames ] */
55239
7c673cae
FG
55240 duk_pop_2(ctx);
55241 duk_remove(ctx, -2);
11fdf7f2
TL
55242
55243 /* [ args [crud] arguments ] */
7c673cae
FG
55244}
55245
55246/* Helper for creating the arguments object and adding it to the env record
55247 * on top of the value stack. This helper has a very strict dependency on
55248 * the shape of the input stack.
55249 */
11fdf7f2
TL
55250DUK_LOCAL void duk__handle_createargs_for_call(duk_hthread *thr,
55251 duk_hobject *func,
55252 duk_hobject *env,
55253 duk_idx_t num_stack_args) {
7c673cae
FG
55254 duk_context *ctx = (duk_context *) thr;
55255
55256 DUK_DDD(DUK_DDDPRINT("creating arguments object for function call"));
55257
55258 DUK_ASSERT(thr != NULL);
55259 DUK_ASSERT(func != NULL);
55260 DUK_ASSERT(env != NULL);
55261 DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
55262 DUK_ASSERT(duk_get_top(ctx) >= num_stack_args + 1);
55263
11fdf7f2 55264 /* [ ... arg1 ... argN envobj ] */
7c673cae
FG
55265
55266 duk__create_arguments_object(thr,
55267 func,
55268 env,
55269 duk_get_top(ctx) - num_stack_args - 1, /* idx_argbase */
55270 num_stack_args);
55271
11fdf7f2 55272 /* [ ... arg1 ... argN envobj argobj ] */
7c673cae
FG
55273
55274 duk_xdef_prop_stridx(ctx,
55275 -2,
55276 DUK_STRIDX_LC_ARGUMENTS,
55277 DUK_HOBJECT_HAS_STRICT(func) ? DUK_PROPDESC_FLAGS_E : /* strict: non-deletable, non-writable */
55278 DUK_PROPDESC_FLAGS_WE); /* non-strict: non-deletable, writable */
11fdf7f2 55279 /* [ ... arg1 ... argN envobj ] */
7c673cae
FG
55280}
55281
55282/*
55283 * Helper for handling a "bound function" chain when a call is being made.
55284 *
55285 * Follows the bound function chain until a non-bound function is found.
55286 * Prepends the bound arguments to the value stack (at idx_func + 2),
55287 * updating 'num_stack_args' in the process. The 'this' binding is also
55288 * updated if necessary (at idx_func + 1). Note that for constructor calls
55289 * the 'this' binding is never updated by [[BoundThis]].
55290 *
55291 * XXX: bound function chains could be collapsed at bound function creation
55292 * time so that each bound function would point directly to a non-bound
55293 * function. This would make call time handling much easier.
55294 */
55295
11fdf7f2
TL
55296DUK_LOCAL void duk__handle_bound_chain_for_call(duk_hthread *thr,
55297 duk_idx_t idx_func,
55298 duk_idx_t *p_num_stack_args, /* may be changed by call */
55299 duk_bool_t is_constructor_call) {
7c673cae
FG
55300 duk_context *ctx = (duk_context *) thr;
55301 duk_idx_t num_stack_args;
55302 duk_tval *tv_func;
55303 duk_hobject *func;
55304 duk_uint_t sanity;
55305
55306 DUK_ASSERT(thr != NULL);
55307 DUK_ASSERT(p_num_stack_args != NULL);
55308
55309 /* On entry, item at idx_func is a bound, non-lightweight function,
55310 * but we don't rely on that below.
55311 */
55312
55313 num_stack_args = *p_num_stack_args;
55314
55315 sanity = DUK_HOBJECT_BOUND_CHAIN_SANITY;
55316 do {
55317 duk_idx_t i, len;
55318
55319 tv_func = duk_require_tval(ctx, idx_func);
55320 DUK_ASSERT(tv_func != NULL);
55321
55322 if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) {
55323 /* Lightweight function: never bound, so terminate. */
55324 break;
55325 } else if (DUK_TVAL_IS_OBJECT(tv_func)) {
55326 func = DUK_TVAL_GET_OBJECT(tv_func);
55327 if (!DUK_HOBJECT_HAS_BOUND(func)) {
55328 /* Normal non-bound function. */
55329 break;
55330 }
55331 } else {
55332 /* Function.prototype.bind() should never let this happen,
55333 * ugly error message is enough.
55334 */
11fdf7f2 55335 DUK_ERROR_INTERNAL_DEFMSG(thr);
7c673cae
FG
55336 }
55337 DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv_func) != NULL);
55338
55339 /* XXX: this could be more compact by accessing the internal properties
55340 * directly as own properties (they cannot be inherited, and are not
55341 * externally visible).
55342 */
55343
55344 DUK_DDD(DUK_DDDPRINT("bound function encountered, ptr=%p, num_stack_args=%ld: %!T",
55345 (void *) DUK_TVAL_GET_OBJECT(tv_func), (long) num_stack_args, tv_func));
55346
55347 /* [ ... func this arg1 ... argN ] */
55348
55349 if (is_constructor_call) {
55350 /* See: tests/ecmascript/test-spec-bound-constructor.js */
55351 DUK_DDD(DUK_DDDPRINT("constructor call: don't update this binding"));
55352 } else {
55353 duk_get_prop_stridx(ctx, idx_func, DUK_STRIDX_INT_THIS);
55354 duk_replace(ctx, idx_func + 1); /* idx_this = idx_func + 1 */
55355 }
55356
55357 /* [ ... func this arg1 ... argN ] */
55358
55359 /* XXX: duk_get_length? */
55360 duk_get_prop_stridx(ctx, idx_func, DUK_STRIDX_INT_ARGS); /* -> [ ... func this arg1 ... argN _Args ] */
55361 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LENGTH); /* -> [ ... func this arg1 ... argN _Args length ] */
55362 len = (duk_idx_t) duk_require_int(ctx, -1);
55363 duk_pop(ctx);
11fdf7f2
TL
55364
55365 duk_require_stack(ctx, len);
7c673cae
FG
55366 for (i = 0; i < len; i++) {
55367 /* XXX: very slow - better to bulk allocate a gap, and copy
55368 * from args_array directly (we know it has a compact array
55369 * part, etc).
55370 */
55371
55372 /* [ ... func this <some bound args> arg1 ... argN _Args ] */
55373 duk_get_prop_index(ctx, -1, i);
55374 duk_insert(ctx, idx_func + 2 + i); /* idx_args = idx_func + 2 */
55375 }
55376 num_stack_args += len; /* must be updated to work properly (e.g. creation of 'arguments') */
55377 duk_pop(ctx);
55378
55379 /* [ ... func this <bound args> arg1 ... argN ] */
55380
55381 duk_get_prop_stridx(ctx, idx_func, DUK_STRIDX_INT_TARGET);
55382 duk_replace(ctx, idx_func); /* replace in stack */
55383
55384 DUK_DDD(DUK_DDDPRINT("bound function handled, num_stack_args=%ld, idx_func=%ld, curr func=%!T",
55385 (long) num_stack_args, (long) idx_func, duk_get_tval(ctx, idx_func)));
55386 } while (--sanity > 0);
55387
55388 if (sanity == 0) {
11fdf7f2 55389 DUK_ERROR_RANGE(thr, DUK_STR_BOUND_CHAIN_LIMIT);
7c673cae
FG
55390 }
55391
55392 DUK_DDD(DUK_DDDPRINT("final non-bound function is: %!T", duk_get_tval(ctx, idx_func)));
55393
11fdf7f2 55394#if defined(DUK_USE_ASSERTIONS)
7c673cae
FG
55395 tv_func = duk_require_tval(ctx, idx_func);
55396 DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func) || DUK_TVAL_IS_OBJECT(tv_func));
55397 if (DUK_TVAL_IS_OBJECT(tv_func)) {
55398 func = DUK_TVAL_GET_OBJECT(tv_func);
55399 DUK_ASSERT(func != NULL);
55400 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
55401 DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func) ||
55402 DUK_HOBJECT_HAS_NATIVEFUNCTION(func));
55403 }
55404#endif
55405
55406 /* write back */
55407 *p_num_stack_args = num_stack_args;
55408}
55409
55410/*
55411 * Helper for setting up var_env and lex_env of an activation,
55412 * assuming it does NOT have the DUK_HOBJECT_FLAG_NEWENV flag.
55413 */
55414
11fdf7f2
TL
55415DUK_LOCAL void duk__handle_oldenv_for_call(duk_hthread *thr,
55416 duk_hobject *func,
55417 duk_activation *act) {
7c673cae
FG
55418 duk_tval *tv;
55419
55420 DUK_ASSERT(thr != NULL);
55421 DUK_ASSERT(func != NULL);
55422 DUK_ASSERT(act != NULL);
55423 DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV(func));
55424 DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func));
55425
55426 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_LEXENV(thr));
55427 if (tv) {
55428 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
55429 DUK_ASSERT(DUK_HOBJECT_IS_ENV(DUK_TVAL_GET_OBJECT(tv)));
55430 act->lex_env = DUK_TVAL_GET_OBJECT(tv);
55431
55432 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_VARENV(thr));
55433 if (tv) {
55434 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
55435 DUK_ASSERT(DUK_HOBJECT_IS_ENV(DUK_TVAL_GET_OBJECT(tv)));
55436 act->var_env = DUK_TVAL_GET_OBJECT(tv);
55437 } else {
55438 act->var_env = act->lex_env;
55439 }
55440 } else {
55441 act->lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
55442 act->var_env = act->lex_env;
55443 }
55444
55445 DUK_HOBJECT_INCREF_ALLOWNULL(thr, act->lex_env);
55446 DUK_HOBJECT_INCREF_ALLOWNULL(thr, act->var_env);
55447}
55448
55449/*
55450 * Helper for updating callee 'caller' property.
55451 */
55452
11fdf7f2 55453#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
7c673cae
FG
55454DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func) {
55455 duk_tval *tv_caller;
55456 duk_hobject *h_tmp;
55457 duk_activation *act_callee;
55458 duk_activation *act_caller;
55459
55460 DUK_ASSERT(thr != NULL);
55461 DUK_ASSERT(func != NULL);
55462 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func)); /* bound chain resolved */
55463 DUK_ASSERT(thr->callstack_top >= 1);
55464
55465 if (DUK_HOBJECT_HAS_STRICT(func)) {
55466 /* Strict functions don't get their 'caller' updated. */
55467 return;
55468 }
55469
55470 act_callee = thr->callstack + thr->callstack_top - 1;
55471 act_caller = (thr->callstack_top >= 2 ? act_callee - 1 : NULL);
55472
11fdf7f2
TL
55473 /* XXX: check .caller writability? */
55474
7c673cae
FG
55475 /* Backup 'caller' property and update its value. */
55476 tv_caller = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_CALLER(thr));
55477 if (tv_caller) {
55478 /* If caller is global/eval code, 'caller' should be set to
55479 * 'null'.
55480 *
55481 * XXX: there is no exotic flag to infer this correctly now.
55482 * The NEWENV flag is used now which works as intended for
55483 * everything (global code, non-strict eval code, and functions)
55484 * except strict eval code. Bound functions are never an issue
55485 * because 'func' has been resolved to a non-bound function.
55486 */
55487
55488 if (act_caller) {
55489 /* act_caller->func may be NULL in some finalization cases,
55490 * just treat like we don't know the caller.
55491 */
55492 if (act_caller->func && !DUK_HOBJECT_HAS_NEWENV(act_caller->func)) {
55493 /* Setting to NULL causes 'caller' to be set to
55494 * 'null' as desired.
55495 */
55496 act_caller = NULL;
55497 }
55498 }
55499
55500 if (DUK_TVAL_IS_OBJECT(tv_caller)) {
55501 h_tmp = DUK_TVAL_GET_OBJECT(tv_caller);
55502 DUK_ASSERT(h_tmp != NULL);
55503 act_callee->prev_caller = h_tmp;
55504
55505 /* Previous value doesn't need refcount changes because its ownership
55506 * is transferred to prev_caller.
55507 */
55508
55509 if (act_caller) {
55510 DUK_ASSERT(act_caller->func != NULL);
55511 DUK_TVAL_SET_OBJECT(tv_caller, act_caller->func);
55512 DUK_TVAL_INCREF(thr, tv_caller);
55513 } else {
55514 DUK_TVAL_SET_NULL(tv_caller); /* no incref */
55515 }
55516 } else {
55517 /* 'caller' must only take on 'null' or function value */
55518 DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_caller));
55519 DUK_ASSERT(act_callee->prev_caller == NULL);
55520 if (act_caller && act_caller->func) {
55521 /* Tolerate act_caller->func == NULL which happens in
55522 * some finalization cases; treat like unknown caller.
55523 */
55524 DUK_TVAL_SET_OBJECT(tv_caller, act_caller->func);
55525 DUK_TVAL_INCREF(thr, tv_caller);
55526 } else {
55527 DUK_TVAL_SET_NULL(tv_caller); /* no incref */
55528 }
55529 }
55530 }
55531}
55532#endif /* DUK_USE_NONSTD_FUNC_CALLER_PROPERTY */
55533
55534/*
55535 * Determine the effective 'this' binding and coerce the current value
55536 * on the valstack to the effective one (in-place, at idx_this).
55537 *
55538 * The current this value in the valstack (at idx_this) represents either:
55539 * - the caller's requested 'this' binding; or
55540 * - a 'this' binding accumulated from the bound function chain
55541 *
55542 * The final 'this' binding for the target function may still be
55543 * different, and is determined as described in E5 Section 10.4.3.
55544 *
55545 * For global and eval code (E5 Sections 10.4.1 and 10.4.2), we assume
55546 * that the caller has provided the correct 'this' binding explicitly
55547 * when calling, i.e.:
55548 *
55549 * - global code: this=global object
55550 * - direct eval: this=copy from eval() caller's this binding
55551 * - other eval: this=global object
55552 *
55553 * Note: this function may cause a recursive function call with arbitrary
55554 * side effects, because ToObject() may be called.
55555 */
55556
11fdf7f2
TL
55557DUK_LOCAL void duk__coerce_effective_this_binding(duk_hthread *thr,
55558 duk_hobject *func,
55559 duk_idx_t idx_this) {
7c673cae 55560 duk_context *ctx = (duk_context *) thr;
11fdf7f2
TL
55561 duk_tval *tv_this;
55562 duk_hobject *obj_global;
7c673cae 55563
11fdf7f2 55564 if (func == NULL || DUK_HOBJECT_HAS_STRICT(func)) {
7c673cae 55565 /* Lightfuncs are always considered strict. */
11fdf7f2
TL
55566 DUK_DDD(DUK_DDDPRINT("this binding: strict -> use directly"));
55567 return;
7c673cae
FG
55568 }
55569
11fdf7f2
TL
55570 /* XXX: byte offset */
55571 tv_this = thr->valstack_bottom + idx_this;
55572 switch (DUK_TVAL_GET_TAG(tv_this)) {
55573 case DUK_TAG_OBJECT:
55574 case DUK_TAG_LIGHTFUNC: /* lightfuncs are treated like objects and not coerced */
55575 DUK_DDD(DUK_DDDPRINT("this binding: non-strict, object -> use directly"));
55576 break;
55577 case DUK_TAG_UNDEFINED:
55578 case DUK_TAG_NULL:
55579 DUK_DDD(DUK_DDDPRINT("this binding: non-strict, undefined/null -> use global object"));
55580 obj_global = thr->builtins[DUK_BIDX_GLOBAL];
55581 /* XXX: avoid this check somehow */
55582 if (DUK_LIKELY(obj_global != NULL)) {
55583 DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_this)); /* no need to decref previous value */
55584 DUK_TVAL_SET_OBJECT(tv_this, obj_global);
55585 DUK_HOBJECT_INCREF(thr, obj_global);
7c673cae 55586 } else {
11fdf7f2
TL
55587 /* This may only happen if built-ins are being "torn down".
55588 * This behavior is out of specification scope.
55589 */
55590 DUK_D(DUK_DPRINT("this binding: wanted to use global object, but it is NULL -> using undefined instead"));
55591 DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_this)); /* no need to decref previous value */
55592 DUK_TVAL_SET_UNDEFINED(tv_this); /* nothing to incref */
7c673cae 55593 }
11fdf7f2
TL
55594 break;
55595 default:
55596 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_this));
55597 DUK_DDD(DUK_DDDPRINT("this binding: non-strict, not object/undefined/null -> use ToObject(value)"));
55598 duk_to_object(ctx, idx_this); /* may have side effects */
55599 break;
7c673cae
FG
55600 }
55601}
55602
55603/*
55604 * Shared helper for non-bound func lookup.
55605 *
55606 * Returns duk_hobject * to the final non-bound function (NULL for lightfunc).
55607 */
55608
11fdf7f2
TL
55609DUK_LOCAL duk_hobject *duk__nonbound_func_lookup(duk_context *ctx,
55610 duk_idx_t idx_func,
55611 duk_idx_t *out_num_stack_args,
55612 duk_tval **out_tv_func,
55613 duk_small_uint_t call_flags) {
7c673cae
FG
55614 duk_hthread *thr = (duk_hthread *) ctx;
55615 duk_tval *tv_func;
55616 duk_hobject *func;
55617
55618 for (;;) {
55619 /* Use loop to minimize code size of relookup after bound function case */
11fdf7f2 55620 tv_func = DUK_GET_TVAL_POSIDX(ctx, idx_func);
7c673cae
FG
55621 DUK_ASSERT(tv_func != NULL);
55622
55623 if (DUK_TVAL_IS_OBJECT(tv_func)) {
55624 func = DUK_TVAL_GET_OBJECT(tv_func);
55625 if (!DUK_HOBJECT_IS_CALLABLE(func)) {
55626 goto not_callable_error;
55627 }
55628 if (DUK_HOBJECT_HAS_BOUND(func)) {
55629 duk__handle_bound_chain_for_call(thr, idx_func, out_num_stack_args, call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL);
55630
55631 /* The final object may be a normal function or a lightfunc.
55632 * We need to re-lookup tv_func because it may have changed
55633 * (also value stack may have been resized). Loop again to
55634 * do that; we're guaranteed not to come here again.
55635 */
55636 DUK_ASSERT(DUK_TVAL_IS_OBJECT(duk_require_tval(ctx, idx_func)) ||
55637 DUK_TVAL_IS_LIGHTFUNC(duk_require_tval(ctx, idx_func)));
55638 continue;
55639 }
55640 } else if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) {
55641 func = NULL;
55642 } else {
55643 goto not_callable_error;
55644 }
55645 break;
55646 }
55647
55648 DUK_ASSERT((DUK_TVAL_IS_OBJECT(tv_func) && DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(tv_func))) ||
55649 DUK_TVAL_IS_LIGHTFUNC(tv_func));
55650 DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUND(func));
55651 DUK_ASSERT(func == NULL || (DUK_HOBJECT_IS_COMPILEDFUNCTION(func) ||
55652 DUK_HOBJECT_IS_NATIVEFUNCTION(func)));
55653
55654 *out_tv_func = tv_func;
55655 return func;
55656
55657 not_callable_error:
11fdf7f2
TL
55658 DUK_ASSERT(tv_func != NULL);
55659#if defined(DUK_USE_PARANOID_ERRORS)
55660 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE);
55661#else
55662 DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not callable", duk_push_string_tval_readable(ctx, tv_func));
55663#endif
7c673cae
FG
55664 DUK_UNREACHABLE();
55665 return NULL; /* never executed */
55666}
55667
55668/*
11fdf7f2 55669 * Value stack resize and stack top adjustment helper.
7c673cae
FG
55670 *
55671 * XXX: This should all be merged to duk_valstack_resize_raw().
55672 */
55673
11fdf7f2
TL
55674DUK_LOCAL void duk__adjust_valstack_and_top(duk_hthread *thr,
55675 duk_idx_t num_stack_args,
55676 duk_idx_t idx_args,
55677 duk_idx_t nregs,
55678 duk_idx_t nargs,
55679 duk_hobject *func) {
7c673cae
FG
55680 duk_context *ctx = (duk_context *) thr;
55681 duk_size_t vs_min_size;
55682 duk_bool_t adjusted_top = 0;
55683
11fdf7f2
TL
55684 vs_min_size = (thr->valstack_bottom - thr->valstack) + /* bottom of current func */
55685 idx_args; /* bottom of new func */
7c673cae
FG
55686
55687 if (nregs >= 0) {
55688 DUK_ASSERT(nargs >= 0);
55689 DUK_ASSERT(nregs >= nargs);
55690 vs_min_size += nregs;
55691 } else {
55692 /* 'func' wants stack "as is" */
55693 vs_min_size += num_stack_args; /* num entries of new func at entry */
55694 }
55695 if (func == NULL || DUK_HOBJECT_IS_NATIVEFUNCTION(func)) {
11fdf7f2 55696 vs_min_size += DUK_VALSTACK_API_ENTRY_MINIMUM; /* Duktape/C API guaranteed entries (on top of args) */
7c673cae 55697 }
11fdf7f2 55698 vs_min_size += DUK_VALSTACK_INTERNAL_EXTRA; /* + spare */
7c673cae 55699
11fdf7f2
TL
55700 /* XXX: We can't resize the value stack to a size smaller than the
55701 * current top, so the order of the resize and adjusting the stack
55702 * top depends on the current vs. final size of the value stack.
55703 * The operations could be combined to avoid this, but the proper
55704 * fix is to only grow the value stack on a function call, and only
55705 * shrink it (without throwing if the shrink fails) on function
55706 * return.
7c673cae
FG
55707 */
55708
55709 if (vs_min_size < (duk_size_t) (thr->valstack_top - thr->valstack)) {
55710 DUK_DDD(DUK_DDDPRINT(("final size smaller, set top before resize")));
55711
55712 DUK_ASSERT(nregs >= 0); /* can't happen when keeping current stack size */
55713 duk_set_top(ctx, idx_args + nargs); /* clamp anything above nargs */
55714 duk_set_top(ctx, idx_args + nregs); /* extend with undefined */
55715 adjusted_top = 1;
55716 }
55717
55718 (void) duk_valstack_resize_raw((duk_context *) thr,
55719 vs_min_size,
55720 DUK_VSRESIZE_FLAG_SHRINK | /* flags */
55721 0 /* no compact */ |
55722 DUK_VSRESIZE_FLAG_THROW);
55723
55724 if (!adjusted_top) {
55725 if (nregs >= 0) {
55726 DUK_ASSERT(nregs >= nargs);
55727 duk_set_top(ctx, idx_args + nargs); /* clamp anything above nargs */
55728 duk_set_top(ctx, idx_args + nregs); /* extend with undefined */
55729 }
55730 }
55731}
55732
55733/*
11fdf7f2
TL
55734 * Manipulate value stack so that exactly 'num_stack_rets' return
55735 * values are at 'idx_retbase' in every case, assuming there are
55736 * 'rc' return values on top of stack.
7c673cae 55737 *
11fdf7f2
TL
55738 * This is a bit tricky, because the called C function operates in
55739 * the same activation record and may have e.g. popped the stack
55740 * empty (below idx_retbase).
55741 */
55742
55743DUK_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) {
55744 duk_context *ctx = (duk_context *) thr;
55745 duk_idx_t idx_rcbase;
55746
55747 DUK_ASSERT(thr != NULL);
55748 DUK_ASSERT(idx_retbase >= 0);
55749 DUK_ASSERT(num_stack_rets >= 0);
55750 DUK_ASSERT(num_actual_rets >= 0);
55751
55752 idx_rcbase = duk_get_top(ctx) - num_actual_rets; /* base of known return values */
55753
55754 DUK_DDD(DUK_DDDPRINT("adjust valstack after func call: "
55755 "num_stack_rets=%ld, num_actual_rets=%ld, stack_top=%ld, idx_retbase=%ld, idx_rcbase=%ld",
55756 (long) num_stack_rets, (long) num_actual_rets, (long) duk_get_top(ctx),
55757 (long) idx_retbase, (long) idx_rcbase));
55758
55759 DUK_ASSERT(idx_rcbase >= 0); /* caller must check */
55760
55761 /* Ensure space for final configuration (idx_retbase + num_stack_rets)
55762 * and intermediate configurations.
55763 */
55764 duk_require_stack_top(ctx,
55765 (idx_rcbase > idx_retbase ? idx_rcbase : idx_retbase) +
55766 num_stack_rets);
55767
55768 /* Chop extra retvals away / extend with undefined. */
55769 duk_set_top(ctx, idx_rcbase + num_stack_rets);
55770
55771 if (idx_rcbase >= idx_retbase) {
55772 duk_idx_t count = idx_rcbase - idx_retbase;
55773 duk_idx_t i;
55774
55775 DUK_DDD(DUK_DDDPRINT("elements at/after idx_retbase have enough to cover func retvals "
55776 "(idx_retbase=%ld, idx_rcbase=%ld)", (long) idx_retbase, (long) idx_rcbase));
55777
55778 /* nuke values at idx_retbase to get the first retval (initially
55779 * at idx_rcbase) to idx_retbase
55780 */
55781
55782 DUK_ASSERT(count >= 0);
55783
55784 for (i = 0; i < count; i++) {
55785 /* XXX: inefficient; block remove primitive */
55786 duk_remove(ctx, idx_retbase);
55787 }
55788 } else {
55789 duk_idx_t count = idx_retbase - idx_rcbase;
55790 duk_idx_t i;
55791
55792 DUK_DDD(DUK_DDDPRINT("not enough elements at/after idx_retbase to cover func retvals "
55793 "(idx_retbase=%ld, idx_rcbase=%ld)", (long) idx_retbase, (long) idx_rcbase));
55794
55795 /* insert 'undefined' values at idx_rcbase to get the
55796 * return values to idx_retbase
55797 */
55798
55799 DUK_ASSERT(count > 0);
55800
55801 for (i = 0; i < count; i++) {
55802 /* XXX: inefficient; block insert primitive */
55803 duk_push_undefined(ctx);
55804 duk_insert(ctx, idx_rcbase);
55805 }
55806 }
55807}
55808
55809/*
55810 * Misc shared helpers.
55811 */
55812
55813/* Get valstack index for the func argument or throw if insane stack. */
55814DUK_LOCAL duk_idx_t duk__get_idx_func(duk_hthread *thr, duk_idx_t num_stack_args) {
55815 duk_size_t off_stack_top;
55816 duk_size_t off_stack_args;
55817 duk_size_t off_stack_all;
55818 duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
55819
55820 /* Argument validation and func/args offset. */
55821 off_stack_top = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack_bottom);
55822 off_stack_args = (duk_size_t) ((duk_size_t) num_stack_args * sizeof(duk_tval));
55823 off_stack_all = off_stack_args + 2 * sizeof(duk_tval);
55824 if (DUK_UNLIKELY(off_stack_all > off_stack_top)) {
55825 /* Since stack indices are not reliable, we can't do anything useful
55826 * here. Invoke the existing setjmp catcher, or if it doesn't exist,
55827 * call the fatal error handler.
55828 */
55829 DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
55830 return 0;
55831 }
55832 idx_func = (duk_idx_t) ((off_stack_top - off_stack_all) / sizeof(duk_tval));
55833 return idx_func;
55834}
55835
55836/*
55837 * duk_handle_call_protected() and duk_handle_call_unprotected():
55838 * call into a Duktape/C or an Ecmascript function from any state.
7c673cae
FG
55839 *
55840 * Input stack (thr):
55841 *
55842 * [ func this arg1 ... argN ]
55843 *
55844 * Output stack (thr):
55845 *
55846 * [ retval ] (DUK_EXEC_SUCCESS)
55847 * [ errobj ] (DUK_EXEC_ERROR (normal error), protected call)
55848 *
11fdf7f2
TL
55849 * Even when executing a protected call an error may be thrown in rare cases
55850 * such as an insane num_stack_args argument. If there is no catchpoint for
55851 * such errors, the fatal error handler is called.
7c673cae 55852 *
11fdf7f2
TL
55853 * The error handling path should be error free, even for out-of-memory
55854 * errors, to ensure safe sandboxing. (As of Duktape 1.4.0 this is not
55855 * yet the case, see XXX notes below.)
7c673cae
FG
55856 */
55857
11fdf7f2
TL
55858DUK_INTERNAL duk_int_t duk_handle_call_protected(duk_hthread *thr,
55859 duk_idx_t num_stack_args,
55860 duk_small_uint_t call_flags) {
55861 duk_context *ctx;
7c673cae
FG
55862 duk_size_t entry_valstack_bottom_index;
55863 duk_size_t entry_valstack_end;
55864 duk_size_t entry_callstack_top;
55865 duk_size_t entry_catchstack_top;
55866 duk_int_t entry_call_recursion_depth;
55867 duk_hthread *entry_curr_thread;
55868 duk_uint_fast8_t entry_thread_state;
55869 duk_instr_t **entry_ptr_curr_pc;
11fdf7f2 55870 duk_jmpbuf *old_jmpbuf_ptr = NULL;
7c673cae 55871 duk_jmpbuf our_jmpbuf;
11fdf7f2 55872 duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
7c673cae 55873
11fdf7f2
TL
55874 /* XXX: Multiple tv_func lookups are now avoided by making a local
55875 * copy of tv_func. Another approach would be to compute an offset
55876 * for tv_func from valstack bottom and recomputing the tv_func
55877 * pointer quickly as valstack + offset instead of calling duk_get_tval().
55878 */
55879
55880 ctx = (duk_context *) thr;
55881 DUK_UNREF(ctx);
7c673cae 55882 DUK_ASSERT(thr != NULL);
11fdf7f2 55883 DUK_ASSERT_CTX_VALID(ctx);
7c673cae 55884 DUK_ASSERT(num_stack_args >= 0);
7c673cae
FG
55885 /* XXX: currently NULL allocations are not supported; remove if later allowed */
55886 DUK_ASSERT(thr->valstack != NULL);
55887 DUK_ASSERT(thr->callstack != NULL);
55888 DUK_ASSERT(thr->catchstack != NULL);
55889
11fdf7f2
TL
55890 /* Argument validation and func/args offset. */
55891 idx_func = duk__get_idx_func(thr, num_stack_args);
55892
55893 /* Preliminaries, required by setjmp() handler. Must be careful not
55894 * to throw an unintended error here.
7c673cae
FG
55895 */
55896
55897 entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
11fdf7f2 55898#if defined(DUK_USE_PREFER_SIZE)
7c673cae 55899 entry_valstack_end = (duk_size_t) (thr->valstack_end - thr->valstack);
11fdf7f2
TL
55900#else
55901 DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack) == thr->valstack_size);
55902 entry_valstack_end = thr->valstack_size;
55903#endif
7c673cae
FG
55904 entry_callstack_top = thr->callstack_top;
55905 entry_catchstack_top = thr->catchstack_top;
55906 entry_call_recursion_depth = thr->heap->call_recursion_depth;
55907 entry_curr_thread = thr->heap->curr_thread; /* Note: may be NULL if first call */
55908 entry_thread_state = thr->state;
55909 entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */
55910
11fdf7f2
TL
55911 DUK_DD(DUK_DDPRINT("duk_handle_call_protected: thr=%p, num_stack_args=%ld, "
55912 "call_flags=0x%08lx (ignorerec=%ld, constructor=%ld), "
7c673cae
FG
55913 "valstack_top=%ld, idx_func=%ld, idx_args=%ld, rec_depth=%ld/%ld, "
55914 "entry_valstack_bottom_index=%ld, entry_callstack_top=%ld, entry_catchstack_top=%ld, "
55915 "entry_call_recursion_depth=%ld, entry_curr_thread=%p, entry_thread_state=%ld",
55916 (void *) thr,
55917 (long) num_stack_args,
55918 (unsigned long) call_flags,
7c673cae
FG
55919 (long) ((call_flags & DUK_CALL_FLAG_IGNORE_RECLIMIT) != 0 ? 1 : 0),
55920 (long) ((call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL) != 0 ? 1 : 0),
7c673cae
FG
55921 (long) duk_get_top(ctx),
55922 (long) idx_func,
11fdf7f2 55923 (long) (idx_func + 2),
7c673cae
FG
55924 (long) thr->heap->call_recursion_depth,
55925 (long) thr->heap->call_recursion_limit,
55926 (long) entry_valstack_bottom_index,
55927 (long) entry_callstack_top,
55928 (long) entry_catchstack_top,
55929 (long) entry_call_recursion_depth,
55930 (void *) entry_curr_thread,
55931 (long) entry_thread_state));
55932
7c673cae
FG
55933 old_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr;
55934 thr->heap->lj.jmpbuf_ptr = &our_jmpbuf;
55935
11fdf7f2
TL
55936#if defined(DUK_USE_CPP_EXCEPTIONS)
55937 try {
55938#else
55939 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == &our_jmpbuf);
55940 if (DUK_SETJMP(our_jmpbuf.jb) == 0) {
55941#endif
55942 /* Call handling and success path. Success path exit cleans
55943 * up almost all state.
7c673cae 55944 */
11fdf7f2 55945 duk__handle_call_inner(thr, num_stack_args, call_flags, idx_func);
7c673cae 55946
11fdf7f2
TL
55947 /* Success path handles */
55948 DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth);
55949 DUK_ASSERT(thr->ptr_curr_pc == entry_ptr_curr_pc);
7c673cae 55950
11fdf7f2
TL
55951 /* Longjmp state is kept clean in success path */
55952 DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
55953 DUK_ASSERT(thr->heap->lj.iserror == 0);
55954 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
55955 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
7c673cae 55956
11fdf7f2 55957 thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
7c673cae 55958
11fdf7f2
TL
55959 return DUK_EXEC_SUCCESS;
55960#if defined(DUK_USE_CPP_EXCEPTIONS)
55961 } catch (duk_internal_exception &exc) {
55962#else
55963 } else {
55964#endif
55965 /* Error; error value is in heap->lj.value1. */
55966
55967#if defined(DUK_USE_CPP_EXCEPTIONS)
55968 DUK_UNREF(exc);
55969#endif
55970
55971 duk__handle_call_error(thr,
55972 entry_valstack_bottom_index,
55973 entry_valstack_end,
55974 entry_catchstack_top,
55975 entry_callstack_top,
55976 entry_call_recursion_depth,
55977 entry_curr_thread,
55978 entry_thread_state,
55979 entry_ptr_curr_pc,
55980 idx_func,
55981 old_jmpbuf_ptr);
55982
55983 /* Longjmp state is cleaned up by error handling */
55984 DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
55985 DUK_ASSERT(thr->heap->lj.iserror == 0);
55986 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
55987 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
55988 return DUK_EXEC_ERROR;
55989 }
55990#if defined(DUK_USE_CPP_EXCEPTIONS)
55991 catch (std::exception &exc) {
55992 const char *what = exc.what();
55993 if (!what) {
55994 what = "unknown";
55995 }
55996 DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
55997 try {
55998 DUK_ERROR_FMT1(thr, DUK_ERR_API_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
55999 } catch (duk_internal_exception exc) {
56000 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
56001 DUK_UNREF(exc);
56002 duk__handle_call_error(thr,
56003 entry_valstack_bottom_index,
56004 entry_valstack_end,
56005 entry_catchstack_top,
56006 entry_callstack_top,
56007 entry_call_recursion_depth,
56008 entry_curr_thread,
56009 entry_thread_state,
56010 entry_ptr_curr_pc,
56011 idx_func,
56012 old_jmpbuf_ptr);
56013 return DUK_EXEC_ERROR;
56014 }
56015 } catch (...) {
56016 DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
56017 try {
56018 DUK_ERROR_API(thr, "caught invalid c++ exception (perhaps thrown by user code)");
56019 } catch (duk_internal_exception exc) {
56020 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
56021 DUK_UNREF(exc);
56022 duk__handle_call_error(thr,
56023 entry_valstack_bottom_index,
56024 entry_valstack_end,
56025 entry_catchstack_top,
56026 entry_callstack_top,
56027 entry_call_recursion_depth,
56028 entry_curr_thread,
56029 entry_thread_state,
56030 entry_ptr_curr_pc,
56031 idx_func,
56032 old_jmpbuf_ptr);
56033 return DUK_EXEC_ERROR;
56034 }
56035 }
56036#endif
56037}
56038
56039DUK_INTERNAL void duk_handle_call_unprotected(duk_hthread *thr,
56040 duk_idx_t num_stack_args,
56041 duk_small_uint_t call_flags) {
56042 duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
7c673cae 56043
11fdf7f2
TL
56044 /* Argument validation and func/args offset. */
56045 idx_func = duk__get_idx_func(thr, num_stack_args);
7c673cae 56046
11fdf7f2
TL
56047 duk__handle_call_inner(thr, num_stack_args, call_flags, idx_func);
56048}
7c673cae 56049
11fdf7f2
TL
56050DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr,
56051 duk_idx_t num_stack_args,
56052 duk_small_uint_t call_flags,
56053 duk_idx_t idx_func) {
56054 duk_context *ctx;
56055 duk_size_t entry_valstack_bottom_index;
56056 duk_size_t entry_valstack_end;
56057 duk_size_t entry_callstack_top;
56058 duk_size_t entry_catchstack_top;
56059 duk_int_t entry_call_recursion_depth;
56060 duk_hthread *entry_curr_thread;
56061 duk_uint_fast8_t entry_thread_state;
56062 duk_instr_t **entry_ptr_curr_pc;
56063 duk_idx_t nargs; /* # argument registers target function wants (< 0 => "as is") */
56064 duk_idx_t nregs; /* # total registers target function wants on entry (< 0 => "as is") */
56065 duk_hobject *func; /* 'func' on stack (borrowed reference) */
56066 duk_tval *tv_func; /* duk_tval ptr for 'func' on stack (borrowed reference) or tv_func_copy */
56067 duk_tval tv_func_copy; /* to avoid relookups */
56068 duk_activation *act;
56069 duk_hobject *env;
56070 duk_ret_t rc;
7c673cae 56071
11fdf7f2
TL
56072 ctx = (duk_context *) thr;
56073 DUK_ASSERT(thr != NULL);
56074 DUK_ASSERT_CTX_VALID(ctx);
56075 DUK_ASSERT(ctx != NULL);
56076 DUK_ASSERT(num_stack_args >= 0);
56077 /* XXX: currently NULL allocations are not supported; remove if later allowed */
56078 DUK_ASSERT(thr->valstack != NULL);
56079 DUK_ASSERT(thr->callstack != NULL);
56080 DUK_ASSERT(thr->catchstack != NULL);
7c673cae 56081
11fdf7f2
TL
56082 DUK_DD(DUK_DDPRINT("duk__handle_call_inner: num_stack_args=%ld, call_flags=0x%08lx, top=%ld",
56083 (long) num_stack_args, (long) call_flags, (long) duk_get_top(ctx)));
7c673cae 56084
11fdf7f2
TL
56085 /*
56086 * Store entry state.
7c673cae
FG
56087 */
56088
11fdf7f2
TL
56089 entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
56090#if defined(DUK_USE_PREFER_SIZE)
56091 entry_valstack_end = (duk_size_t) (thr->valstack_end - thr->valstack);
56092#else
56093 DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack) == thr->valstack_size);
56094 entry_valstack_end = thr->valstack_size;
56095#endif
56096 entry_callstack_top = thr->callstack_top;
56097 entry_catchstack_top = thr->catchstack_top;
56098 entry_call_recursion_depth = thr->heap->call_recursion_depth;
56099 entry_curr_thread = thr->heap->curr_thread; /* Note: may be NULL if first call */
56100 entry_thread_state = thr->state;
56101 entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */
7c673cae 56102
11fdf7f2
TL
56103 /* If thr->ptr_curr_pc is set, sync curr_pc to act->pc. Then NULL
56104 * thr->ptr_curr_pc so that it's not accidentally used with an incorrect
56105 * activation when side effects occur.
7c673cae 56106 */
11fdf7f2
TL
56107 duk_hthread_sync_and_null_currpc(thr);
56108
56109 DUK_DD(DUK_DDPRINT("duk__handle_call_inner: thr=%p, num_stack_args=%ld, "
56110 "call_flags=0x%08lx (ignorerec=%ld, constructor=%ld), "
56111 "valstack_top=%ld, idx_func=%ld, idx_args=%ld, rec_depth=%ld/%ld, "
56112 "entry_valstack_bottom_index=%ld, entry_callstack_top=%ld, entry_catchstack_top=%ld, "
56113 "entry_call_recursion_depth=%ld, entry_curr_thread=%p, entry_thread_state=%ld",
56114 (void *) thr,
56115 (long) num_stack_args,
56116 (unsigned long) call_flags,
56117 (long) ((call_flags & DUK_CALL_FLAG_IGNORE_RECLIMIT) != 0 ? 1 : 0),
56118 (long) ((call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL) != 0 ? 1 : 0),
56119 (long) duk_get_top(ctx),
56120 (long) idx_func,
56121 (long) (idx_func + 2),
56122 (long) thr->heap->call_recursion_depth,
56123 (long) thr->heap->call_recursion_limit,
56124 (long) entry_valstack_bottom_index,
56125 (long) entry_callstack_top,
56126 (long) entry_catchstack_top,
56127 (long) entry_call_recursion_depth,
56128 (void *) entry_curr_thread,
56129 (long) entry_thread_state));
56130
7c673cae 56131
7c673cae
FG
56132 /*
56133 * Thread state check and book-keeping.
56134 */
56135
56136 if (thr == thr->heap->curr_thread) {
56137 /* same thread */
56138 if (thr->state != DUK_HTHREAD_STATE_RUNNING) {
56139 /* should actually never happen, but check anyway */
56140 goto thread_state_error;
56141 }
56142 } else {
56143 /* different thread */
56144 DUK_ASSERT(thr->heap->curr_thread == NULL ||
56145 thr->heap->curr_thread->state == DUK_HTHREAD_STATE_RUNNING);
56146 if (thr->state != DUK_HTHREAD_STATE_INACTIVE) {
56147 goto thread_state_error;
56148 }
56149 DUK_HEAP_SWITCH_THREAD(thr->heap, thr);
56150 thr->state = DUK_HTHREAD_STATE_RUNNING;
56151
56152 /* Note: multiple threads may be simultaneously in the RUNNING
56153 * state, but not in the same "resume chain".
56154 */
56155 }
7c673cae
FG
56156 DUK_ASSERT(thr->heap->curr_thread == thr);
56157 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
56158
56159 /*
56160 * C call recursion depth check, which provides a reasonable upper
56161 * bound on maximum C stack size (arbitrary C stack growth is only
56162 * possible by recursive handle_call / handle_safe_call calls).
56163 */
56164
11fdf7f2
TL
56165 /* XXX: remove DUK_CALL_FLAG_IGNORE_RECLIMIT flag: there's now the
56166 * reclimit bump?
56167 */
56168
7c673cae
FG
56169 DUK_ASSERT(thr->heap->call_recursion_depth >= 0);
56170 DUK_ASSERT(thr->heap->call_recursion_depth <= thr->heap->call_recursion_limit);
7c673cae
FG
56171 if (call_flags & DUK_CALL_FLAG_IGNORE_RECLIMIT) {
56172 DUK_DD(DUK_DDPRINT("ignoring reclimit for this call (probably an errhandler call)"));
56173 } else {
56174 if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit) {
56175 /* XXX: error message is a bit misleading: we reached a recursion
56176 * limit which is also essentially the same as a C callstack limit
56177 * (except perhaps with some relaxed threading assumptions).
56178 */
11fdf7f2 56179 DUK_ERROR_RANGE(thr, DUK_STR_C_CALLSTACK_LIMIT);
7c673cae
FG
56180 }
56181 thr->heap->call_recursion_depth++;
56182 }
56183
56184 /*
56185 * Check the function type, handle bound function chains, and prepare
56186 * parameters for the rest of the call handling. Also figure out the
56187 * effective 'this' binding, which replaces the current value at
56188 * idx_func + 1.
56189 *
56190 * If the target function is a 'bound' one, follow the chain of 'bound'
56191 * functions until a non-bound function is found. During this process,
56192 * bound arguments are 'prepended' to existing ones, and the "this"
56193 * binding is overridden. See E5 Section 15.3.4.5.1.
56194 *
56195 * Lightfunc detection happens here too. Note that lightweight functions
56196 * can be wrapped by (non-lightweight) bound functions so we must resolve
56197 * the bound function chain first.
56198 */
56199
56200 func = duk__nonbound_func_lookup(ctx, idx_func, &num_stack_args, &tv_func, call_flags);
56201 DUK_TVAL_SET_TVAL(&tv_func_copy, tv_func);
56202 tv_func = &tv_func_copy; /* local copy to avoid relookups */
56203
56204 DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUND(func));
56205 DUK_ASSERT(func == NULL || (DUK_HOBJECT_IS_COMPILEDFUNCTION(func) ||
56206 DUK_HOBJECT_IS_NATIVEFUNCTION(func)));
56207
56208 duk__coerce_effective_this_binding(thr, func, idx_func + 1);
56209 DUK_DDD(DUK_DDDPRINT("effective 'this' binding is: %!T",
56210 (duk_tval *) duk_get_tval(ctx, idx_func + 1)));
56211
7c673cae
FG
56212 /* [ ... func this arg1 ... argN ] */
56213
56214 /*
11fdf7f2 56215 * Setup a preliminary activation and figure out nargs/nregs.
7c673cae
FG
56216 *
56217 * Don't touch valstack_bottom or valstack_top yet so that Duktape API
56218 * calls work normally.
56219 */
56220
56221 duk_hthread_callstack_grow(thr);
56222
56223 if (thr->callstack_top > 0) {
56224 /*
56225 * Update idx_retval of current activation.
56226 *
56227 * Although it might seem this is not necessary (bytecode executor
56228 * does this for Ecmascript-to-Ecmascript calls; other calls are
56229 * handled here), this turns out to be necessary for handling yield
56230 * and resume. For them, an Ecmascript-to-native call happens, and
56231 * the Ecmascript call's idx_retval must be set for things to work.
56232 */
56233
56234 (thr->callstack + thr->callstack_top - 1)->idx_retval = entry_valstack_bottom_index + idx_func;
56235 }
56236
56237 DUK_ASSERT(thr->callstack_top < thr->callstack_size);
56238 act = thr->callstack + thr->callstack_top;
56239 thr->callstack_top++;
56240 DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
56241 DUK_ASSERT(thr->valstack_top > thr->valstack_bottom); /* at least effective 'this' */
56242 DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUND(func));
56243
56244 act->flags = 0;
11fdf7f2
TL
56245
56246 /* For now all calls except Ecma-to-Ecma calls prevent a yield. */
56247 act->flags |= DUK_ACT_FLAG_PREVENT_YIELD;
7c673cae
FG
56248 if (call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL) {
56249 act->flags |= DUK_ACT_FLAG_CONSTRUCT;
7c673cae
FG
56250 }
56251 if (call_flags & DUK_CALL_FLAG_DIRECT_EVAL) {
56252 act->flags |= DUK_ACT_FLAG_DIRECT_EVAL;
56253 }
56254
11fdf7f2
TL
56255 /* These base values are never used, but if the compiler doesn't know
56256 * that DUK_ERROR() won't return, these are needed to silence warnings.
56257 * On the other hand, scan-build will warn about the values not being
56258 * used, so add a DUK_UNREF.
7c673cae 56259 */
11fdf7f2
TL
56260 nargs = 0; DUK_UNREF(nargs);
56261 nregs = 0; DUK_UNREF(nregs);
56262
56263 if (DUK_LIKELY(func != NULL)) {
56264 if (DUK_HOBJECT_HAS_STRICT(func)) {
56265 act->flags |= DUK_ACT_FLAG_STRICT;
56266 }
56267 if (DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
56268 nargs = ((duk_hcompiledfunction *) func)->nargs;
56269 nregs = ((duk_hcompiledfunction *) func)->nregs;
56270 DUK_ASSERT(nregs >= nargs);
56271 } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(func)) {
56272 /* Note: nargs (and nregs) may be negative for a native,
56273 * function, which indicates that the function wants the
56274 * input stack "as is" (i.e. handles "vararg" arguments).
56275 */
56276 nargs = ((duk_hnativefunction *) func)->nargs;
56277 nregs = nargs;
56278 } else {
56279 /* XXX: this should be an assert */
56280 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE);
56281 }
56282 } else {
56283 duk_small_uint_t lf_flags;
56284
56285 DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func));
56286 lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv_func);
56287 nargs = DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
56288 if (nargs == DUK_LFUNC_NARGS_VARARGS) {
56289 nargs = -1; /* vararg */
56290 }
56291 nregs = nargs;
56292
56293 act->flags |= DUK_ACT_FLAG_STRICT;
56294 }
7c673cae
FG
56295
56296 act->func = func; /* NULL for lightfunc */
56297 act->var_env = NULL;
56298 act->lex_env = NULL;
11fdf7f2 56299#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
7c673cae
FG
56300 act->prev_caller = NULL;
56301#endif
56302 act->curr_pc = NULL;
56303#if defined(DUK_USE_DEBUGGER_SUPPORT)
56304 act->prev_line = 0;
56305#endif
11fdf7f2 56306 act->idx_bottom = entry_valstack_bottom_index + idx_func + 2;
7c673cae
FG
56307#if 0 /* topmost activation idx_retval is considered garbage, no need to init */
56308 act->idx_retval = 0;
56309#endif
56310 DUK_TVAL_SET_TVAL(&act->tv_func, tv_func); /* borrowed, no refcount */
56311
11fdf7f2
TL
56312 /* XXX: remove the preventcount and make yield walk the callstack?
56313 * Or perhaps just use a single flag, not a counter, faster to just
56314 * set and restore?
56315 */
7c673cae
FG
56316 if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
56317 /* duk_hthread_callstack_unwind() will decrease this on unwind */
56318 thr->callstack_preventcount++;
56319 }
56320
56321 /* XXX: Is this INCREF necessary? 'func' is always a borrowed
56322 * reference reachable through the value stack? If changed, stack
56323 * unwind code also needs to be fixed to match.
56324 */
56325 DUK_HOBJECT_INCREF_ALLOWNULL(thr, func); /* act->func */
56326
11fdf7f2 56327#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
7c673cae
FG
56328 if (func) {
56329 duk__update_func_caller_prop(thr, func);
11fdf7f2 56330 act = thr->callstack + thr->callstack_top - 1;
7c673cae 56331 }
7c673cae
FG
56332#endif
56333
11fdf7f2 56334 /* [ ... func this arg1 ... argN ] */
7c673cae
FG
56335
56336 /*
56337 * Environment record creation and 'arguments' object creation.
56338 * Named function expression name binding is handled by the
56339 * compiler; the compiled function's parent env will contain
56340 * the (immutable) binding already.
56341 *
56342 * This handling is now identical for C and Ecmascript functions.
56343 * C functions always have the 'NEWENV' flag set, so their
56344 * environment record initialization is delayed (which is good).
56345 *
56346 * Delayed creation (on demand) is handled in duk_js_var.c.
56347 */
56348
56349 DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUND(func)); /* bound function chain has already been resolved */
56350
11fdf7f2
TL
56351 if (DUK_LIKELY(func != NULL)) {
56352 if (DUK_LIKELY(DUK_HOBJECT_HAS_NEWENV(func))) {
56353 if (DUK_LIKELY(!DUK_HOBJECT_HAS_CREATEARGS(func))) {
56354 /* Use a new environment but there's no 'arguments' object;
56355 * delayed environment initialization. This is the most
56356 * common case.
56357 */
56358 DUK_ASSERT(act->lex_env == NULL);
56359 DUK_ASSERT(act->var_env == NULL);
56360 } else {
56361 /* Use a new environment and there's an 'arguments' object.
56362 * We need to initialize it right now.
56363 */
7c673cae 56364
11fdf7f2
TL
56365 /* third arg: absolute index (to entire valstack) of idx_bottom of new activation */
56366 env = duk_create_activation_environment_record(thr, func, act->idx_bottom);
56367 DUK_ASSERT(env != NULL);
7c673cae 56368
11fdf7f2 56369 /* [ ... func this arg1 ... argN envobj ] */
7c673cae 56370
11fdf7f2
TL
56371 DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
56372 duk__handle_createargs_for_call(thr, func, env, num_stack_args);
7c673cae 56373
11fdf7f2 56374 /* [ ... func this arg1 ... argN envobj ] */
7c673cae 56375
11fdf7f2
TL
56376 act = thr->callstack + thr->callstack_top - 1;
56377 act->lex_env = env;
56378 act->var_env = env;
56379 DUK_HOBJECT_INCREF(thr, env);
56380 DUK_HOBJECT_INCREF(thr, env); /* XXX: incref by count (2) directly */
56381 duk_pop(ctx);
56382 }
56383 } else {
56384 /* Use existing env (e.g. for non-strict eval); cannot have
56385 * an own 'arguments' object (but can refer to an existing one).
56386 */
7c673cae 56387
11fdf7f2 56388 DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func));
7c673cae 56389
11fdf7f2
TL
56390 duk__handle_oldenv_for_call(thr, func, act);
56391 /* No need to re-lookup 'act' at present: no side effects. */
7c673cae 56392
11fdf7f2
TL
56393 DUK_ASSERT(act->lex_env != NULL);
56394 DUK_ASSERT(act->var_env != NULL);
56395 }
56396 } else {
56397 /* Lightfuncs are always native functions and have "newenv". */
56398 DUK_ASSERT(act->lex_env == NULL);
56399 DUK_ASSERT(act->var_env == NULL);
56400 }
7c673cae 56401
11fdf7f2 56402 /* [ ... func this arg1 ... argN ] */
7c673cae
FG
56403
56404 /*
56405 * Setup value stack: clamp to 'nargs', fill up to 'nregs'
56406 *
56407 * Value stack may either grow or shrink, depending on the
56408 * number of func registers and the number of actual arguments.
56409 * If nregs >= 0, func wants args clamped to 'nargs'; else it
56410 * wants all args (= 'num_stack_args').
56411 */
56412
11fdf7f2
TL
56413 /* XXX: optimize value stack operation */
56414 /* XXX: don't want to shrink allocation here */
56415
7c673cae
FG
56416 duk__adjust_valstack_and_top(thr,
56417 num_stack_args,
11fdf7f2 56418 idx_func + 2,
7c673cae
FG
56419 nregs,
56420 nargs,
56421 func);
56422
56423 /*
11fdf7f2
TL
56424 * Determine call type, then finalize activation, shift to
56425 * new value stack bottom, and call the target.
7c673cae
FG
56426 */
56427
11fdf7f2 56428 act = thr->callstack + thr->callstack_top - 1;
7c673cae 56429 if (func != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
11fdf7f2
TL
56430 /*
56431 * Ecmascript call
56432 */
7c673cae 56433
11fdf7f2
TL
56434 duk_tval *tv_ret;
56435 duk_tval *tv_funret;
7c673cae 56436
11fdf7f2
TL
56437 DUK_ASSERT(func != NULL);
56438 DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func));
56439 act->curr_pc = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, (duk_hcompiledfunction *) func);
7c673cae 56440
11fdf7f2
TL
56441 thr->valstack_bottom = thr->valstack_bottom + idx_func + 2;
56442 /* keep current valstack_top */
56443 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
56444 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
56445 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
7c673cae 56446
11fdf7f2 56447 /* [ ... func this | arg1 ... argN ] ('this' must precede new bottom) */
7c673cae 56448
11fdf7f2
TL
56449 /*
56450 * Bytecode executor call.
56451 *
56452 * Execute bytecode, handling any recursive function calls and
56453 * thread resumptions. Returns when execution would return from
56454 * the entry level activation. When the executor returns, a
56455 * single return value is left on the stack top.
56456 *
56457 * The only possible longjmp() is an error (DUK_LJ_TYPE_THROW),
56458 * other types are handled internally by the executor.
56459 */
7c673cae 56460
11fdf7f2
TL
56461 /* thr->ptr_curr_pc is set by bytecode executor early on entry */
56462 DUK_ASSERT(thr->ptr_curr_pc == NULL);
56463 DUK_DDD(DUK_DDDPRINT("entering bytecode execution"));
56464 duk_js_execute_bytecode(thr);
56465 DUK_DDD(DUK_DDDPRINT("returned from bytecode execution"));
7c673cae 56466
11fdf7f2 56467 /* Unwind. */
7c673cae 56468
11fdf7f2
TL
56469 DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top); /* may need unwind */
56470 DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
56471 DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
56472 duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
56473 duk_hthread_catchstack_shrink_check(thr);
56474 duk_hthread_callstack_unwind(thr, entry_callstack_top);
56475 duk_hthread_callstack_shrink_check(thr);
7c673cae 56476
11fdf7f2
TL
56477 thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
56478 /* keep current valstack_top */
56479 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
56480 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
56481 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
56482 DUK_ASSERT(thr->valstack_top - thr->valstack_bottom >= idx_func + 1);
7c673cae 56483
11fdf7f2 56484 /* Return value handling. */
7c673cae 56485
11fdf7f2
TL
56486 /* [ ... func this (crud) retval ] */
56487
56488 tv_ret = thr->valstack_bottom + idx_func;
56489 tv_funret = thr->valstack_top - 1;
56490#if defined(DUK_USE_FASTINT)
56491 /* Explicit check for fastint downgrade. */
56492 DUK_TVAL_CHKFAST_INPLACE(tv_funret);
7c673cae 56493#endif
11fdf7f2
TL
56494 DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, tv_funret); /* side effects */
56495 } else {
56496 /*
56497 * Native call.
56498 */
7c673cae 56499
11fdf7f2
TL
56500 duk_tval *tv_ret;
56501 duk_tval *tv_funret;
7c673cae 56502
11fdf7f2
TL
56503 thr->valstack_bottom = thr->valstack_bottom + idx_func + 2;
56504 /* keep current valstack_top */
56505 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
56506 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
56507 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
56508 DUK_ASSERT(func == NULL || ((duk_hnativefunction *) func)->func != NULL);
7c673cae 56509
11fdf7f2 56510 /* [ ... func this | arg1 ... argN ] ('this' must precede new bottom) */
7c673cae 56511
11fdf7f2
TL
56512 /* For native calls must be NULL so we don't sync back */
56513 DUK_ASSERT(thr->ptr_curr_pc == NULL);
56514
56515 if (func) {
56516 rc = ((duk_hnativefunction *) func)->func((duk_context *) thr);
56517 } else {
56518 duk_c_function funcptr = DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv_func);
56519 rc = funcptr((duk_context *) thr);
56520 }
56521
56522 /* Automatic error throwing, retval check. */
7c673cae 56523
11fdf7f2
TL
56524 if (rc < 0) {
56525 duk_error_throw_from_negative_rc(thr, rc);
56526 DUK_UNREACHABLE();
56527 } else if (rc > 1) {
56528 DUK_ERROR_API(thr, "c function returned invalid rc");
56529 }
56530 DUK_ASSERT(rc == 0 || rc == 1);
7c673cae 56531
11fdf7f2 56532 /* Unwind. */
7c673cae 56533
11fdf7f2
TL
56534 DUK_ASSERT(thr->catchstack_top == entry_catchstack_top); /* no need to unwind */
56535 DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
56536 duk_hthread_callstack_unwind(thr, entry_callstack_top);
56537 duk_hthread_callstack_shrink_check(thr);
56538
56539 thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
56540 /* keep current valstack_top */
56541 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
56542 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
56543 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
56544 DUK_ASSERT(thr->valstack_top - thr->valstack_bottom >= idx_func + 1);
56545
56546 /* Return value handling. */
56547
56548 /* XXX: should this happen in the callee's activation or after unwinding? */
56549 tv_ret = thr->valstack_bottom + idx_func;
56550 if (rc == 0) {
56551 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv_ret); /* side effects */
56552 } else {
56553 /* [ ... func this (crud) retval ] */
56554 tv_funret = thr->valstack_top - 1;
56555#if defined(DUK_USE_FASTINT)
56556 /* Explicit check for fastint downgrade. */
56557 DUK_TVAL_CHKFAST_INPLACE(tv_funret);
56558#endif
56559 DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, tv_funret); /* side effects */
56560 }
56561 }
56562
56563 duk_set_top(ctx, idx_func + 1); /* XXX: unnecessary, handle in adjust */
56564
56565 /* [ ... retval ] */
7c673cae
FG
56566
56567 /* Ensure there is internal valstack spare before we exit; this may
56568 * throw an alloc error. The same guaranteed size must be available
56569 * as before the call. This is not optimal now: we store the valstack
56570 * allocated size during entry; this value may be higher than the
56571 * minimal guarantee for an application.
56572 */
56573
11fdf7f2
TL
56574 /* XXX: we should never shrink here; when we error out later, we'd
56575 * need to potentially grow the value stack in error unwind which could
56576 * cause another error.
56577 */
56578
7c673cae
FG
56579 (void) duk_valstack_resize_raw((duk_context *) thr,
56580 entry_valstack_end, /* same as during entry */
56581 DUK_VSRESIZE_FLAG_SHRINK | /* flags */
56582 DUK_VSRESIZE_FLAG_COMPACT |
56583 DUK_VSRESIZE_FLAG_THROW);
56584
11fdf7f2
TL
56585 /* Restore entry thread executor curr_pc stack frame pointer. */
56586 thr->ptr_curr_pc = entry_ptr_curr_pc;
7c673cae 56587
11fdf7f2
TL
56588 DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */
56589 thr->state = (duk_uint8_t) entry_thread_state;
56590
56591 DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */
56592 (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */
56593 (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */
7c673cae 56594
11fdf7f2 56595 thr->heap->call_recursion_depth = entry_call_recursion_depth;
7c673cae 56596
11fdf7f2
TL
56597 /* If the debugger is active we need to force an interrupt so that
56598 * debugger breakpoints are rechecked. This is important for function
56599 * calls caused by side effects (e.g. when doing a DUK_OP_GETPROP), see
56600 * GH-303. Only needed for success path, error path always causes a
56601 * breakpoint recheck in the executor. It would be enough to set this
56602 * only when returning to an Ecmascript activation, but setting the flag
56603 * on every return should have no ill effect.
7c673cae 56604 */
11fdf7f2
TL
56605#if defined(DUK_USE_DEBUGGER_SUPPORT)
56606 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
56607 DUK_DD(DUK_DDPRINT("returning with debugger enabled, force interrupt"));
56608 DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init);
56609 thr->interrupt_init -= thr->interrupt_counter;
56610 thr->interrupt_counter = 0;
56611 thr->heap->dbg_force_restart = 1;
56612 }
56613#endif
7c673cae 56614
11fdf7f2
TL
56615#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
56616 duk__interrupt_fixup(thr, entry_curr_thread);
56617#endif
7c673cae 56618
11fdf7f2 56619 return;
7c673cae 56620
11fdf7f2
TL
56621 thread_state_error:
56622 DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "invalid thread state for call (%ld)", (long) thr->state);
56623 DUK_UNREACHABLE();
56624 return; /* never executed */
56625}
56626
56627DUK_LOCAL void duk__handle_call_error(duk_hthread *thr,
56628 duk_size_t entry_valstack_bottom_index,
56629 duk_size_t entry_valstack_end,
56630 duk_size_t entry_catchstack_top,
56631 duk_size_t entry_callstack_top,
56632 duk_int_t entry_call_recursion_depth,
56633 duk_hthread *entry_curr_thread,
56634 duk_uint_fast8_t entry_thread_state,
56635 duk_instr_t **entry_ptr_curr_pc,
56636 duk_idx_t idx_func,
56637 duk_jmpbuf *old_jmpbuf_ptr) {
56638 duk_context *ctx;
56639 duk_tval *tv_ret;
7c673cae 56640
11fdf7f2 56641 ctx = (duk_context *) thr;
7c673cae 56642
11fdf7f2
TL
56643 DUK_DDD(DUK_DDDPRINT("error caught during duk__handle_call_inner(): %!T",
56644 (duk_tval *) &thr->heap->lj.value1));
7c673cae 56645
11fdf7f2
TL
56646 /* Other longjmp types are handled by executor before propagating
56647 * the error here.
7c673cae 56648 */
11fdf7f2
TL
56649 DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW);
56650 DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
56651 DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
7c673cae 56652
11fdf7f2
TL
56653 /* We don't need to sync back thr->ptr_curr_pc here because
56654 * the bytecode executor always has a setjmp catchpoint which
56655 * does that before errors propagate to here.
56656 */
7c673cae 56657 DUK_ASSERT(thr->ptr_curr_pc == NULL);
7c673cae 56658
11fdf7f2
TL
56659 /* Restore the previous setjmp catcher so that any error in
56660 * error handling will propagate outwards rather than re-enter
56661 * the same handler. However, the error handling path must be
56662 * designed to be error free so that sandboxing guarantees are
56663 * reliable, see e.g. https://github.com/svaarala/duktape/issues/476.
7c673cae 56664 */
11fdf7f2 56665 thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
7c673cae 56666
11fdf7f2
TL
56667 /* XXX: callstack unwind may now throw an error when closing
56668 * scopes; this is a sandboxing issue, described in:
56669 * https://github.com/svaarala/duktape/issues/476
56670 */
7c673cae 56671 duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
11fdf7f2 56672 duk_hthread_catchstack_shrink_check(thr);
7c673cae 56673 duk_hthread_callstack_unwind(thr, entry_callstack_top);
11fdf7f2 56674 duk_hthread_callstack_shrink_check(thr);
7c673cae
FG
56675
56676 thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
11fdf7f2
TL
56677 tv_ret = thr->valstack_bottom + idx_func; /* XXX: byte offset? */
56678 DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, &thr->heap->lj.value1); /* side effects */
56679#if defined(DUK_USE_FASTINT)
56680 /* Explicit check for fastint downgrade. */
56681 DUK_TVAL_CHKFAST_INPLACE(tv_ret);
56682#endif
56683 duk_set_top(ctx, idx_func + 1); /* XXX: could be eliminated with valstack adjust */
7c673cae 56684
11fdf7f2 56685 /* [ ... errobj ] */
7c673cae
FG
56686
56687 /* Ensure there is internal valstack spare before we exit; this may
56688 * throw an alloc error. The same guaranteed size must be available
56689 * as before the call. This is not optimal now: we store the valstack
56690 * allocated size during entry; this value may be higher than the
56691 * minimal guarantee for an application.
56692 */
56693
11fdf7f2
TL
56694 /* XXX: this needs to be reworked so that we never shrink the value
56695 * stack on function entry so that we never need to grow it here.
56696 * Needing to grow here is a sandboxing issue because we need to
56697 * allocate which may cause an error in the error handling path
56698 * and thus propagate an error out of a protected call.
56699 */
56700
7c673cae
FG
56701 (void) duk_valstack_resize_raw((duk_context *) thr,
56702 entry_valstack_end, /* same as during entry */
56703 DUK_VSRESIZE_FLAG_SHRINK | /* flags */
56704 DUK_VSRESIZE_FLAG_COMPACT |
56705 DUK_VSRESIZE_FLAG_THROW);
56706
7c673cae 56707
11fdf7f2
TL
56708 /* These are just convenience "wiping" of state. Side effects should
56709 * not be an issue here: thr->heap and thr->heap->lj have a stable
56710 * pointer. Finalizer runs etc capture even out-of-memory errors so
56711 * nothing should throw here.
56712 */
56713 thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
56714 thr->heap->lj.iserror = 0;
56715 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */
56716 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */
7c673cae
FG
56717
56718 /* Restore entry thread executor curr_pc stack frame pointer. */
56719 thr->ptr_curr_pc = entry_ptr_curr_pc;
56720
56721 DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */
56722 thr->state = (duk_uint8_t) entry_thread_state;
56723
56724 DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */
56725 (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */
56726 (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */
56727
56728 thr->heap->call_recursion_depth = entry_call_recursion_depth;
56729
56730 /* If the debugger is active we need to force an interrupt so that
56731 * debugger breakpoints are rechecked. This is important for function
56732 * calls caused by side effects (e.g. when doing a DUK_OP_GETPROP), see
56733 * GH-303. Only needed for success path, error path always causes a
56734 * breakpoint recheck in the executor. It would be enough to set this
56735 * only when returning to an Ecmascript activation, but setting the flag
56736 * on every return should have no ill effect.
56737 */
56738#if defined(DUK_USE_DEBUGGER_SUPPORT)
56739 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
11fdf7f2 56740 DUK_DD(DUK_DDPRINT("returning with debugger enabled, force interrupt"));
7c673cae
FG
56741 DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init);
56742 thr->interrupt_init -= thr->interrupt_counter;
56743 thr->interrupt_counter = 0;
56744 thr->heap->dbg_force_restart = 1;
56745 }
56746#endif
56747
56748#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
56749 duk__interrupt_fixup(thr, entry_curr_thread);
56750#endif
7c673cae
FG
56751}
56752
56753/*
11fdf7f2
TL
56754 * duk_handle_safe_call(): make a "C protected call" within the
56755 * current activation.
7c673cae
FG
56756 *
56757 * The allowed thread states for making a call are the same as for
11fdf7f2 56758 * duk_handle_call_xxx().
7c673cae 56759 *
11fdf7f2
TL
56760 * Error handling is similar to duk_handle_call_xxx(); errors may be thrown
56761 * (and result in a fatal error) for insane arguments.
7c673cae
FG
56762 */
56763
56764/* XXX: bump preventcount by one for the duration of this call? */
56765
11fdf7f2
TL
56766DUK_INTERNAL duk_int_t duk_handle_safe_call(duk_hthread *thr,
56767 duk_safe_call_function func,
56768 duk_idx_t num_stack_args,
56769 duk_idx_t num_stack_rets) {
7c673cae
FG
56770 duk_context *ctx = (duk_context *) thr;
56771 duk_size_t entry_valstack_bottom_index;
56772 duk_size_t entry_callstack_top;
56773 duk_size_t entry_catchstack_top;
56774 duk_int_t entry_call_recursion_depth;
56775 duk_hthread *entry_curr_thread;
56776 duk_uint_fast8_t entry_thread_state;
56777 duk_instr_t **entry_ptr_curr_pc;
56778 duk_jmpbuf *old_jmpbuf_ptr = NULL;
56779 duk_jmpbuf our_jmpbuf;
7c673cae
FG
56780 duk_idx_t idx_retbase;
56781 duk_int_t retval;
7c673cae
FG
56782
56783 DUK_ASSERT(thr != NULL);
56784 DUK_ASSERT(ctx != NULL);
56785
56786 /* Note: careful with indices like '-x'; if 'x' is zero, it refers to bottom */
56787 entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
56788 entry_callstack_top = thr->callstack_top;
56789 entry_catchstack_top = thr->catchstack_top;
56790 entry_call_recursion_depth = thr->heap->call_recursion_depth;
56791 entry_curr_thread = thr->heap->curr_thread; /* Note: may be NULL if first call */
56792 entry_thread_state = thr->state;
56793 entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */
56794 idx_retbase = duk_get_top(ctx) - num_stack_args; /* Note: not a valid stack index if num_stack_args == 0 */
56795
56796 /* Note: cannot portably debug print a function pointer, hence 'func' not printed! */
56797 DUK_DD(DUK_DDPRINT("duk_handle_safe_call: thr=%p, num_stack_args=%ld, num_stack_rets=%ld, "
56798 "valstack_top=%ld, idx_retbase=%ld, rec_depth=%ld/%ld, "
56799 "entry_valstack_bottom_index=%ld, entry_callstack_top=%ld, entry_catchstack_top=%ld, "
56800 "entry_call_recursion_depth=%ld, entry_curr_thread=%p, entry_thread_state=%ld",
56801 (void *) thr,
56802 (long) num_stack_args,
56803 (long) num_stack_rets,
56804 (long) duk_get_top(ctx),
56805 (long) idx_retbase,
56806 (long) thr->heap->call_recursion_depth,
56807 (long) thr->heap->call_recursion_limit,
56808 (long) entry_valstack_bottom_index,
56809 (long) entry_callstack_top,
56810 (long) entry_catchstack_top,
56811 (long) entry_call_recursion_depth,
56812 (void *) entry_curr_thread,
56813 (long) entry_thread_state));
56814
56815 if (idx_retbase < 0) {
11fdf7f2
TL
56816 /* Since stack indices are not reliable, we can't do anything useful
56817 * here. Invoke the existing setjmp catcher, or if it doesn't exist,
56818 * call the fatal error handler.
7c673cae
FG
56819 */
56820
11fdf7f2 56821 DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
7c673cae
FG
56822 }
56823
56824 /* setjmp catchpoint setup */
56825
56826 old_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr;
56827 thr->heap->lj.jmpbuf_ptr = &our_jmpbuf;
56828
11fdf7f2
TL
56829#if defined(DUK_USE_CPP_EXCEPTIONS)
56830 try {
56831#else
56832 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == &our_jmpbuf);
56833 if (DUK_SETJMP(our_jmpbuf.jb) == 0) {
56834 /* Success path. */
56835#endif
56836 DUK_DDD(DUK_DDDPRINT("safe_call setjmp catchpoint setup complete"));
56837
56838 duk__handle_safe_call_inner(thr,
56839 func,
56840 idx_retbase,
56841 num_stack_rets,
56842 entry_valstack_bottom_index,
56843 entry_callstack_top,
56844 entry_catchstack_top);
56845
56846 /* Longjmp state is kept clean in success path */
56847 DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
56848 DUK_ASSERT(thr->heap->lj.iserror == 0);
56849 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
56850 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
56851
56852 /* Note: either pointer may be NULL (at entry), so don't assert */
56853 thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
7c673cae 56854
11fdf7f2
TL
56855 retval = DUK_EXEC_SUCCESS;
56856#if defined(DUK_USE_CPP_EXCEPTIONS)
56857 } catch (duk_internal_exception &exc) {
56858 DUK_UNREF(exc);
56859#else
56860 } else {
56861 /* Error path. */
56862#endif
56863 duk__handle_safe_call_error(thr,
56864 idx_retbase,
56865 num_stack_rets,
56866 entry_valstack_bottom_index,
56867 entry_callstack_top,
56868 entry_catchstack_top,
56869 old_jmpbuf_ptr);
56870
56871 /* Longjmp state is cleaned up by error handling */
56872 DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
56873 DUK_ASSERT(thr->heap->lj.iserror == 0);
56874 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
56875 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
56876
56877 retval = DUK_EXEC_ERROR;
56878 }
56879#if defined(DUK_USE_CPP_EXCEPTIONS)
56880 catch (std::exception &exc) {
56881 const char *what = exc.what();
56882 if (!what) {
56883 what = "unknown";
56884 }
56885 DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
56886 try {
56887 DUK_ERROR_FMT1(thr, DUK_ERR_API_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
56888 } catch (duk_internal_exception exc) {
56889 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
56890 DUK_UNREF(exc);
56891 duk__handle_safe_call_error(thr,
56892 idx_retbase,
56893 num_stack_rets,
56894 entry_valstack_bottom_index,
56895 entry_callstack_top,
56896 entry_catchstack_top,
56897 old_jmpbuf_ptr);
56898 retval = DUK_EXEC_ERROR;
56899 }
56900 } catch (...) {
56901 DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
56902 try {
56903 DUK_ERROR_API(thr, "caught invalid c++ exception (perhaps thrown by user code)");
56904 } catch (duk_internal_exception exc) {
56905 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
56906 DUK_UNREF(exc);
56907 duk__handle_safe_call_error(thr,
56908 idx_retbase,
56909 num_stack_rets,
56910 entry_valstack_bottom_index,
56911 entry_callstack_top,
56912 entry_catchstack_top,
56913 old_jmpbuf_ptr);
56914 retval = DUK_EXEC_ERROR;
56915 }
56916 }
56917#endif
56918
56919 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == old_jmpbuf_ptr); /* success/error path both do this */
56920
56921 duk__handle_safe_call_shared(thr,
56922 idx_retbase,
56923 num_stack_rets,
56924 entry_call_recursion_depth,
56925 entry_curr_thread,
56926 entry_thread_state,
56927 entry_ptr_curr_pc);
7c673cae 56928
11fdf7f2
TL
56929 return retval;
56930}
7c673cae 56931
11fdf7f2
TL
56932DUK_LOCAL void duk__handle_safe_call_inner(duk_hthread *thr,
56933 duk_safe_call_function func,
56934 duk_idx_t idx_retbase,
56935 duk_idx_t num_stack_rets,
56936 duk_size_t entry_valstack_bottom_index,
56937 duk_size_t entry_callstack_top,
56938 duk_size_t entry_catchstack_top) {
56939 duk_context *ctx;
56940 duk_ret_t rc;
7c673cae 56941
11fdf7f2
TL
56942 DUK_ASSERT(thr != NULL);
56943 ctx = (duk_context *) thr;
56944 DUK_ASSERT_CTX_VALID(ctx);
56945 DUK_UNREF(entry_valstack_bottom_index);
56946 DUK_UNREF(entry_callstack_top);
56947 DUK_UNREF(entry_catchstack_top);
7c673cae
FG
56948
56949 /*
56950 * Thread state check and book-keeping.
56951 */
56952
56953 if (thr == thr->heap->curr_thread) {
56954 /* same thread */
56955 if (thr->state != DUK_HTHREAD_STATE_RUNNING) {
56956 /* should actually never happen, but check anyway */
56957 goto thread_state_error;
56958 }
56959 } else {
56960 /* different thread */
56961 DUK_ASSERT(thr->heap->curr_thread == NULL ||
56962 thr->heap->curr_thread->state == DUK_HTHREAD_STATE_RUNNING);
56963 if (thr->state != DUK_HTHREAD_STATE_INACTIVE) {
56964 goto thread_state_error;
56965 }
56966 DUK_HEAP_SWITCH_THREAD(thr->heap, thr);
56967 thr->state = DUK_HTHREAD_STATE_RUNNING;
56968
56969 /* Note: multiple threads may be simultaneously in the RUNNING
56970 * state, but not in the same "resume chain".
56971 */
56972 }
56973
56974 DUK_ASSERT(thr->heap->curr_thread == thr);
56975 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
56976
56977 /*
56978 * Recursion limit check.
56979 *
56980 * Note: there is no need for an "ignore recursion limit" flag
56981 * for duk_handle_safe_call now.
56982 */
56983
56984 DUK_ASSERT(thr->heap->call_recursion_depth >= 0);
56985 DUK_ASSERT(thr->heap->call_recursion_depth <= thr->heap->call_recursion_limit);
56986 if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit) {
56987 /* XXX: error message is a bit misleading: we reached a recursion
56988 * limit which is also essentially the same as a C callstack limit
56989 * (except perhaps with some relaxed threading assumptions).
56990 */
11fdf7f2 56991 DUK_ERROR_RANGE(thr, DUK_STR_C_CALLSTACK_LIMIT);
7c673cae
FG
56992 }
56993 thr->heap->call_recursion_depth++;
56994
56995 /*
56996 * Valstack spare check
56997 */
56998
56999 duk_require_stack(ctx, 0); /* internal spare */
57000
57001 /*
57002 * Make the C call
57003 */
57004
57005 rc = func(ctx);
57006
57007 DUK_DDD(DUK_DDDPRINT("safe_call, func rc=%ld", (long) rc));
57008
57009 /*
11fdf7f2 57010 * Valstack manipulation for results.
7c673cae
FG
57011 */
57012
57013 /* we're running inside the caller's activation, so no change in call/catch stack or valstack bottom */
57014 DUK_ASSERT(thr->callstack_top == entry_callstack_top);
57015 DUK_ASSERT(thr->catchstack_top == entry_catchstack_top);
57016 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
57017 DUK_ASSERT((duk_size_t) (thr->valstack_bottom - thr->valstack) == entry_valstack_bottom_index);
57018 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
57019 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
57020
57021 if (rc < 0) {
57022 duk_error_throw_from_negative_rc(thr, rc);
57023 }
57024 DUK_ASSERT(rc >= 0);
57025
57026 if (duk_get_top(ctx) < rc) {
11fdf7f2 57027 DUK_ERROR_API(thr, "not enough stack values for safe_call rc");
7c673cae
FG
57028 }
57029
11fdf7f2
TL
57030 DUK_ASSERT(thr->catchstack_top == entry_catchstack_top); /* no need to unwind */
57031 DUK_ASSERT(thr->callstack_top == entry_callstack_top);
57032
7c673cae 57033 duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, rc);
11fdf7f2 57034 return;
7c673cae 57035
11fdf7f2
TL
57036 thread_state_error:
57037 DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "invalid thread state for safe_call (%ld)", (long) thr->state);
57038 DUK_UNREACHABLE();
57039}
57040
57041DUK_LOCAL void duk__handle_safe_call_error(duk_hthread *thr,
57042 duk_idx_t idx_retbase,
57043 duk_idx_t num_stack_rets,
57044 duk_size_t entry_valstack_bottom_index,
57045 duk_size_t entry_callstack_top,
57046 duk_size_t entry_catchstack_top,
57047 duk_jmpbuf *old_jmpbuf_ptr) {
57048 duk_context *ctx;
57049
57050 DUK_ASSERT(thr != NULL);
57051 ctx = (duk_context *) thr;
57052 DUK_ASSERT_CTX_VALID(ctx);
57053
57054 /*
57055 * Error during call. The error value is at heap->lj.value1.
57056 *
57057 * The very first thing we do is restore the previous setjmp catcher.
57058 * This means that any error in error handling will propagate outwards
57059 * instead of causing a setjmp() re-entry above.
57060 */
7c673cae 57061
11fdf7f2
TL
57062 DUK_DDD(DUK_DDDPRINT("error caught during protected duk_handle_safe_call()"));
57063
57064 /* Other longjmp types are handled by executor before propagating
57065 * the error here.
57066 */
57067 DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW);
57068 DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
57069 DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
57070
57071 /* Note: either pointer may be NULL (at entry), so don't assert. */
57072 thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
57073
57074 DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
57075 DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
57076 duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
7c673cae 57077 duk_hthread_catchstack_shrink_check(thr);
11fdf7f2 57078 duk_hthread_callstack_unwind(thr, entry_callstack_top);
7c673cae 57079 duk_hthread_callstack_shrink_check(thr);
11fdf7f2 57080 thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
7c673cae 57081
11fdf7f2 57082 /* [ ... | (crud) ] */
7c673cae 57083
11fdf7f2
TL
57084 /* XXX: space in valstack? see discussion in duk_handle_call_xxx(). */
57085 duk_push_tval(ctx, &thr->heap->lj.value1);
57086
57087 /* [ ... | (crud) errobj ] */
57088
57089 DUK_ASSERT(duk_get_top(ctx) >= 1); /* at least errobj must be on stack */
57090
57091 /* check that the valstack has space for the final amount and any
57092 * intermediate space needed; this is unoptimal but should be safe
57093 */
57094 duk_require_stack_top(ctx, idx_retbase + num_stack_rets); /* final configuration */
57095 duk_require_stack(ctx, num_stack_rets);
57096
57097 duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, 1); /* 1 = num actual 'return values' */
57098
57099 /* [ ... | ] or [ ... | errobj (M * undefined)] where M = num_stack_rets - 1 */
7c673cae 57100
11fdf7f2
TL
57101 /* These are just convenience "wiping" of state. Side effects should
57102 * not be an issue here: thr->heap and thr->heap->lj have a stable
57103 * pointer. Finalizer runs etc capture even out-of-memory errors so
57104 * nothing should throw here.
7c673cae 57105 */
11fdf7f2
TL
57106 thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
57107 thr->heap->lj.iserror = 0;
57108 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */
57109 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */
57110}
7c673cae 57111
11fdf7f2
TL
57112DUK_LOCAL void duk__handle_safe_call_shared(duk_hthread *thr,
57113 duk_idx_t idx_retbase,
57114 duk_idx_t num_stack_rets,
57115 duk_int_t entry_call_recursion_depth,
57116 duk_hthread *entry_curr_thread,
57117 duk_uint_fast8_t entry_thread_state,
57118 duk_instr_t **entry_ptr_curr_pc) {
57119 duk_context *ctx;
7c673cae 57120
11fdf7f2
TL
57121 DUK_ASSERT(thr != NULL);
57122 ctx = (duk_context *) thr;
57123 DUK_ASSERT_CTX_VALID(ctx);
57124 DUK_UNREF(ctx);
57125 DUK_UNREF(idx_retbase);
57126 DUK_UNREF(num_stack_rets);
7c673cae
FG
57127
57128 /* Restore entry thread executor curr_pc stack frame pointer. */
57129 thr->ptr_curr_pc = entry_ptr_curr_pc;
57130
57131 /* XXX: because we unwind stacks above, thr->heap->curr_thread is at
57132 * risk of pointing to an already freed thread. This was indeed the
57133 * case in test-bug-multithread-valgrind.c, until duk_handle_call()
57134 * was fixed to restore thr->heap->curr_thread before rethrowing an
57135 * uncaught error.
57136 */
57137 DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */
57138 thr->state = (duk_uint8_t) entry_thread_state;
57139
57140 DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */
57141 (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */
57142 (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */
57143
57144 thr->heap->call_recursion_depth = entry_call_recursion_depth;
57145
57146 /* stack discipline consistency check */
57147 DUK_ASSERT(duk_get_top(ctx) == idx_retbase + num_stack_rets);
57148
57149 /* A debugger forced interrupt check is not needed here, as
57150 * problematic safe calls are not caused by side effects.
57151 */
57152
57153#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
57154 duk__interrupt_fixup(thr, entry_curr_thread);
57155#endif
7c673cae
FG
57156}
57157
57158/*
57159 * Helper for handling an Ecmascript-to-Ecmascript call or an Ecmascript
57160 * function (initial) Duktape.Thread.resume().
57161 *
57162 * Compared to normal calls handled by duk_handle_call(), there are a
57163 * bunch of differences:
57164 *
57165 * - the call is never protected
57166 * - there is no C recursion depth increase (hence an "ignore recursion
57167 * limit" flag is not applicable)
57168 * - instead of making the call, this helper just performs the thread
57169 * setup and returns; the bytecode executor then restarts execution
57170 * internally
57171 * - ecmascript functions are never 'vararg' functions (they access
57172 * varargs through the 'arguments' object)
57173 *
57174 * The callstack of the target contains an earlier Ecmascript call in case
57175 * of an Ecmascript-to-Ecmascript call (whose idx_retval is updated), or
57176 * is empty in case of an initial Duktape.Thread.resume().
57177 *
57178 * The first thing to do here is to figure out whether an ecma-to-ecma
57179 * call is actually possible. It's not always the case if the target is
57180 * a bound function; the final function may be native. In that case,
57181 * return an error so caller can fall back to a normal call path.
57182 */
57183
11fdf7f2
TL
57184DUK_INTERNAL duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
57185 duk_idx_t num_stack_args,
57186 duk_small_uint_t call_flags) {
7c673cae
FG
57187 duk_context *ctx = (duk_context *) thr;
57188 duk_size_t entry_valstack_bottom_index;
57189 duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
57190 duk_idx_t idx_args; /* valstack index of start of args (arg1) (relative to entry valstack_bottom) */
57191 duk_idx_t nargs; /* # argument registers target function wants (< 0 => never for ecma calls) */
57192 duk_idx_t nregs; /* # total registers target function wants on entry (< 0 => never for ecma calls) */
57193 duk_hobject *func; /* 'func' on stack (borrowed reference) */
57194 duk_tval *tv_func; /* duk_tval ptr for 'func' on stack (borrowed reference) */
57195 duk_activation *act;
57196 duk_hobject *env;
57197 duk_bool_t use_tailcall;
57198 duk_instr_t **entry_ptr_curr_pc;
57199
57200 DUK_ASSERT(thr != NULL);
57201 DUK_ASSERT(ctx != NULL);
57202 DUK_ASSERT(!((call_flags & DUK_CALL_FLAG_IS_RESUME) != 0 && (call_flags & DUK_CALL_FLAG_IS_TAILCALL) != 0));
57203
57204 /* XXX: assume these? */
57205 DUK_ASSERT(thr->valstack != NULL);
57206 DUK_ASSERT(thr->callstack != NULL);
57207 DUK_ASSERT(thr->catchstack != NULL);
57208
57209 /* no need to handle thread state book-keeping here */
57210 DUK_ASSERT((call_flags & DUK_CALL_FLAG_IS_RESUME) != 0 ||
57211 (thr->state == DUK_HTHREAD_STATE_RUNNING &&
57212 thr->heap->curr_thread == thr));
57213
57214 /* If thr->ptr_curr_pc is set, sync curr_pc to act->pc. Then NULL
57215 * thr->ptr_curr_pc so that it's not accidentally used with an incorrect
57216 * activation when side effects occur. If we end up not making the
57217 * call we must restore the value.
57218 */
57219 entry_ptr_curr_pc = thr->ptr_curr_pc;
57220 duk_hthread_sync_and_null_currpc(thr);
57221
57222 /* if a tail call:
57223 * - an Ecmascript activation must be on top of the callstack
57224 * - there cannot be any active catchstack entries
57225 */
11fdf7f2 57226#if defined(DUK_USE_ASSERTIONS)
7c673cae
FG
57227 if (call_flags & DUK_CALL_FLAG_IS_TAILCALL) {
57228 duk_size_t our_callstack_index;
57229 duk_size_t i;
57230
57231 DUK_ASSERT(thr->callstack_top >= 1);
57232 our_callstack_index = thr->callstack_top - 1;
57233 DUK_ASSERT_DISABLE(our_callstack_index >= 0);
57234 DUK_ASSERT(our_callstack_index < thr->callstack_size);
57235 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + our_callstack_index) != NULL);
57236 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + our_callstack_index)));
57237
57238 /* No entry in the catchstack which would actually catch a
57239 * throw can refer to the callstack entry being reused.
57240 * There *can* be catchstack entries referring to the current
57241 * callstack entry as long as they don't catch (e.g. label sites).
57242 */
57243
57244 for (i = 0; i < thr->catchstack_top; i++) {
57245 DUK_ASSERT(thr->catchstack[i].callstack_index < our_callstack_index || /* refer to callstack entries below current */
57246 DUK_CAT_GET_TYPE(thr->catchstack + i) == DUK_CAT_TYPE_LABEL); /* or a non-catching entry */
57247 }
57248 }
57249#endif /* DUK_USE_ASSERTIONS */
57250
57251 entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
11fdf7f2 57252 /* XXX: rework */
7c673cae
FG
57253 idx_func = duk_normalize_index(thr, -num_stack_args - 2);
57254 idx_args = idx_func + 2;
57255
57256 DUK_DD(DUK_DDPRINT("handle_ecma_call_setup: thr=%p, "
57257 "num_stack_args=%ld, call_flags=0x%08lx (resume=%ld, tailcall=%ld), "
57258 "idx_func=%ld, idx_args=%ld, entry_valstack_bottom_index=%ld",
57259 (void *) thr,
57260 (long) num_stack_args,
57261 (unsigned long) call_flags,
57262 (long) ((call_flags & DUK_CALL_FLAG_IS_RESUME) != 0 ? 1 : 0),
57263 (long) ((call_flags & DUK_CALL_FLAG_IS_TAILCALL) != 0 ? 1 : 0),
57264 (long) idx_func,
57265 (long) idx_args,
57266 (long) entry_valstack_bottom_index));
57267
11fdf7f2 57268 if (DUK_UNLIKELY(idx_func < 0 || idx_args < 0)) {
7c673cae 57269 /* XXX: assert? compiler is responsible for this never happening */
11fdf7f2 57270 DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
7c673cae
FG
57271 }
57272
57273 /*
57274 * Check the function type, handle bound function chains, and prepare
57275 * parameters for the rest of the call handling. Also figure out the
57276 * effective 'this' binding, which replaces the current value at
57277 * idx_func + 1.
57278 *
57279 * If the target function is a 'bound' one, follow the chain of 'bound'
57280 * functions until a non-bound function is found. During this process,
57281 * bound arguments are 'prepended' to existing ones, and the "this"
57282 * binding is overridden. See E5 Section 15.3.4.5.1.
57283 *
57284 * If the final target function cannot be handled by an ecma-to-ecma
57285 * call, return to the caller with a return value indicating this case.
57286 * The bound chain is resolved and the caller can resume with a plain
57287 * function call.
57288 */
57289
57290 func = duk__nonbound_func_lookup(ctx, idx_func, &num_stack_args, &tv_func, call_flags);
57291 if (func == NULL || !DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
57292 DUK_DDD(DUK_DDDPRINT("final target is a lightfunc/nativefunc, cannot do ecma-to-ecma call"));
57293 thr->ptr_curr_pc = entry_ptr_curr_pc;
57294 return 0;
57295 }
57296 /* XXX: tv_func is not actually needed */
57297
57298 DUK_ASSERT(func != NULL);
57299 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
57300 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(func));
57301
57302 duk__coerce_effective_this_binding(thr, func, idx_func + 1);
57303 DUK_DDD(DUK_DDDPRINT("effective 'this' binding is: %!T",
57304 duk_get_tval(ctx, idx_func + 1)));
57305
57306 nargs = ((duk_hcompiledfunction *) func)->nargs;
57307 nregs = ((duk_hcompiledfunction *) func)->nregs;
57308 DUK_ASSERT(nregs >= nargs);
57309
57310 /* [ ... func this arg1 ... argN ] */
57311
57312 /*
57313 * Preliminary activation record and valstack manipulation.
57314 * The concrete actions depend on whether the we're dealing
57315 * with a tail call (reuse an existing activation), a resume,
57316 * or a normal call.
57317 *
57318 * The basic actions, in varying order, are:
57319 *
57320 * - Check stack size for call handling
57321 * - Grow call stack if necessary (non-tail-calls)
57322 * - Update current activation (idx_retval) if necessary
57323 * (non-tail, non-resume calls)
57324 * - Move start of args (idx_args) to valstack bottom
57325 * (tail calls)
57326 *
57327 * Don't touch valstack_bottom or valstack_top yet so that Duktape API
57328 * calls work normally.
57329 */
57330
57331 /* XXX: some overlapping code; cleanup */
57332 use_tailcall = call_flags & DUK_CALL_FLAG_IS_TAILCALL;
57333#if !defined(DUK_USE_TAILCALL)
57334 DUK_ASSERT(use_tailcall == 0); /* compiler ensures this */
57335#endif
57336 if (use_tailcall) {
57337 /* tailcall cannot be flagged to resume calls, and a
57338 * previous frame must exist
57339 */
57340 DUK_ASSERT(thr->callstack_top >= 1);
57341 DUK_ASSERT((call_flags & DUK_CALL_FLAG_IS_RESUME) == 0);
57342
57343 act = thr->callstack + thr->callstack_top - 1;
57344 if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
57345 /* See: test-bug-tailcall-preventyield-assert.c. */
57346 DUK_DDD(DUK_DDDPRINT("tail call prevented by current activation having DUK_ACT_FLAG_PREVENTYIELD"));
57347 use_tailcall = 0;
57348 } else if (DUK_HOBJECT_HAS_NOTAIL(func)) {
57349 DUK_D(DUK_DPRINT("tail call prevented by function having a notail flag"));
57350 use_tailcall = 0;
57351 }
57352 }
57353
57354 if (use_tailcall) {
57355 duk_tval *tv1, *tv2;
7c673cae
FG
57356 duk_size_t cs_index;
57357 duk_int_t i_stk; /* must be signed for loop structure */
57358 duk_idx_t i_arg;
57359
57360 /*
57361 * Tailcall handling
57362 *
57363 * Although the callstack entry is reused, we need to explicitly unwind
57364 * the current activation (or simulate an unwind). In particular, the
57365 * current activation must be closed, otherwise something like
57366 * test-bug-reduce-judofyr.js results. Also catchstack needs be unwound
57367 * because there may be non-error-catching label entries in valid tail calls.
57368 */
57369
57370 DUK_DDD(DUK_DDDPRINT("is tail call, reusing activation at callstack top, at index %ld",
57371 (long) (thr->callstack_top - 1)));
57372
57373 /* 'act' already set above */
57374
57375 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
57376 DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(func));
57377 DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func));
57378 DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0);
57379
57380 /* Unwind catchstack entries referring to the callstack entry we're reusing */
57381 cs_index = thr->callstack_top - 1;
57382 DUK_ASSERT(thr->catchstack_top <= DUK_INT_MAX); /* catchstack limits */
57383 for (i_stk = (duk_int_t) (thr->catchstack_top - 1); i_stk >= 0; i_stk--) {
57384 duk_catcher *cat = thr->catchstack + i_stk;
57385 if (cat->callstack_index != cs_index) {
57386 /* 'i' is the first entry we'll keep */
57387 break;
57388 }
57389 }
57390 duk_hthread_catchstack_unwind(thr, i_stk + 1);
57391
57392 /* Unwind the topmost callstack entry before reusing it */
57393 DUK_ASSERT(thr->callstack_top > 0);
57394 duk_hthread_callstack_unwind(thr, thr->callstack_top - 1);
57395
57396 /* Then reuse the unwound activation; callstack was not shrunk so there is always space */
57397 thr->callstack_top++;
57398 DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
57399 act = thr->callstack + thr->callstack_top - 1;
57400
57401 /* Start filling in the activation */
57402 act->func = func; /* don't want an intermediate exposed state with func == NULL */
11fdf7f2 57403#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
7c673cae
FG
57404 act->prev_caller = NULL;
57405#endif
57406 DUK_ASSERT(func != NULL);
57407 DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func));
57408 /* don't want an intermediate exposed state with invalid pc */
57409 act->curr_pc = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, (duk_hcompiledfunction *) func);
57410#if defined(DUK_USE_DEBUGGER_SUPPORT)
57411 act->prev_line = 0;
57412#endif
57413 DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */
11fdf7f2 57414#if defined(DUK_USE_REFERENCE_COUNTING)
7c673cae
FG
57415 DUK_HOBJECT_INCREF(thr, func);
57416 act = thr->callstack + thr->callstack_top - 1; /* side effects (currently none though) */
57417#endif
57418
11fdf7f2
TL
57419#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
57420#if defined(DUK_USE_TAILCALL)
7c673cae
FG
57421#error incorrect options: tail calls enabled with function caller property
57422#endif
57423 /* XXX: this doesn't actually work properly for tail calls, so
57424 * tail calls are disabled when DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
57425 * is in use.
57426 */
57427 duk__update_func_caller_prop(thr, func);
57428 act = thr->callstack + thr->callstack_top - 1;
57429#endif
57430
57431 act->flags = (DUK_HOBJECT_HAS_STRICT(func) ?
57432 DUK_ACT_FLAG_STRICT | DUK_ACT_FLAG_TAILCALLED :
57433 DUK_ACT_FLAG_TAILCALLED);
57434
57435 DUK_ASSERT(DUK_ACT_GET_FUNC(act) == func); /* already updated */
57436 DUK_ASSERT(act->var_env == NULL); /* already NULLed (by unwind) */
57437 DUK_ASSERT(act->lex_env == NULL); /* already NULLed (by unwind) */
57438 act->idx_bottom = entry_valstack_bottom_index; /* tail call -> reuse current "frame" */
57439 DUK_ASSERT(nregs >= 0);
57440#if 0 /* topmost activation idx_retval is considered garbage, no need to init */
57441 act->idx_retval = 0;
57442#endif
57443
57444 /*
57445 * Manipulate valstack so that args are on the current bottom and the
57446 * previous caller's 'this' binding (which is the value preceding the
57447 * current bottom) is replaced with the new 'this' binding:
57448 *
57449 * [ ... this_old | (crud) func this_new arg1 ... argN ]
57450 * --> [ ... this_new | arg1 ... argN ]
57451 *
57452 * For tail calling to work properly, the valstack bottom must not grow
57453 * here; otherwise crud would accumulate on the valstack.
57454 */
57455
57456 tv1 = thr->valstack_bottom - 1;
57457 tv2 = thr->valstack_bottom + idx_func + 1;
57458 DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top); /* tv1 is -below- valstack_bottom */
57459 DUK_ASSERT(tv2 >= thr->valstack_bottom && tv2 < thr->valstack_top);
11fdf7f2 57460 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
7c673cae
FG
57461
57462 for (i_arg = 0; i_arg < idx_args; i_arg++) {
57463 /* XXX: block removal API primitive */
57464 /* Note: 'func' is popped from valstack here, but it is
57465 * already reachable from the activation.
57466 */
57467 duk_remove(ctx, 0);
57468 }
57469 idx_func = 0; DUK_UNREF(idx_func); /* really 'not applicable' anymore, should not be referenced after this */
57470 idx_args = 0;
57471
57472 /* [ ... this_new | arg1 ... argN ] */
57473 } else {
57474 DUK_DDD(DUK_DDDPRINT("not a tail call, pushing a new activation to callstack, to index %ld",
57475 (long) (thr->callstack_top)));
57476
57477 duk_hthread_callstack_grow(thr);
57478
57479 if (call_flags & DUK_CALL_FLAG_IS_RESUME) {
57480 DUK_DDD(DUK_DDDPRINT("is resume -> no update to current activation (may not even exist)"));
57481 } else {
57482 DUK_DDD(DUK_DDDPRINT("update to current activation idx_retval"));
57483 DUK_ASSERT(thr->callstack_top < thr->callstack_size);
57484 DUK_ASSERT(thr->callstack_top >= 1);
57485 act = thr->callstack + thr->callstack_top - 1;
57486 DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
57487 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(act)));
57488 act->idx_retval = entry_valstack_bottom_index + idx_func;
57489 }
57490
57491 DUK_ASSERT(thr->callstack_top < thr->callstack_size);
57492 act = thr->callstack + thr->callstack_top;
57493 thr->callstack_top++;
57494 DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
57495
57496 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
57497 DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(func));
57498 DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func));
57499
57500 act->flags = (DUK_HOBJECT_HAS_STRICT(func) ?
57501 DUK_ACT_FLAG_STRICT :
57502 0);
57503 act->func = func;
57504 act->var_env = NULL;
57505 act->lex_env = NULL;
11fdf7f2 57506#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
7c673cae
FG
57507 act->prev_caller = NULL;
57508#endif
57509 DUK_ASSERT(func != NULL);
57510 DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func));
57511 act->curr_pc = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, (duk_hcompiledfunction *) func);
57512#if defined(DUK_USE_DEBUGGER_SUPPORT)
57513 act->prev_line = 0;
57514#endif
57515 act->idx_bottom = entry_valstack_bottom_index + idx_args;
57516 DUK_ASSERT(nregs >= 0);
57517#if 0 /* topmost activation idx_retval is considered garbage, no need to init */
57518 act->idx_retval = 0;
57519#endif
57520 DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */
57521
57522 DUK_HOBJECT_INCREF(thr, func); /* act->func */
57523
11fdf7f2 57524#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
7c673cae
FG
57525 duk__update_func_caller_prop(thr, func);
57526 act = thr->callstack + thr->callstack_top - 1;
57527#endif
57528 }
57529
11fdf7f2
TL
57530 /* [ ... func this arg1 ... argN ] (not tail call)
57531 * [ this | arg1 ... argN ] (tail call)
7c673cae
FG
57532 *
57533 * idx_args updated to match
57534 */
57535
57536 /*
57537 * Environment record creation and 'arguments' object creation.
57538 * Named function expression name binding is handled by the
57539 * compiler; the compiled function's parent env will contain
57540 * the (immutable) binding already.
57541 *
57542 * Delayed creation (on demand) is handled in duk_js_var.c.
57543 */
57544
11fdf7f2
TL
57545 /* XXX: unify handling with native call. */
57546
7c673cae
FG
57547 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func)); /* bound function chain has already been resolved */
57548
57549 if (!DUK_HOBJECT_HAS_NEWENV(func)) {
57550 /* use existing env (e.g. for non-strict eval); cannot have
57551 * an own 'arguments' object (but can refer to the existing one)
57552 */
57553
57554 duk__handle_oldenv_for_call(thr, func, act);
11fdf7f2 57555 /* No need to re-lookup 'act' at present: no side effects. */
7c673cae
FG
57556
57557 DUK_ASSERT(act->lex_env != NULL);
57558 DUK_ASSERT(act->var_env != NULL);
57559 goto env_done;
57560 }
57561
57562 DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
57563
57564 if (!DUK_HOBJECT_HAS_CREATEARGS(func)) {
57565 /* no need to create environment record now; leave as NULL */
57566 DUK_ASSERT(act->lex_env == NULL);
57567 DUK_ASSERT(act->var_env == NULL);
57568 goto env_done;
57569 }
57570
57571 /* third arg: absolute index (to entire valstack) of idx_bottom of new activation */
57572 env = duk_create_activation_environment_record(thr, func, act->idx_bottom);
57573 DUK_ASSERT(env != NULL);
57574
11fdf7f2 57575 /* [ ... arg1 ... argN envobj ] */
7c673cae
FG
57576
57577 /* original input stack before nargs/nregs handling must be
57578 * intact for 'arguments' object
57579 */
57580 DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
57581 duk__handle_createargs_for_call(thr, func, env, num_stack_args);
57582
11fdf7f2 57583 /* [ ... arg1 ... argN envobj ] */
7c673cae
FG
57584
57585 act = thr->callstack + thr->callstack_top - 1;
57586 act->lex_env = env;
57587 act->var_env = env;
57588 DUK_HOBJECT_INCREF(thr, act->lex_env);
57589 DUK_HOBJECT_INCREF(thr, act->var_env);
57590 duk_pop(ctx);
57591
57592 env_done:
11fdf7f2 57593 /* [ ... arg1 ... argN ] */
7c673cae
FG
57594
57595 /*
57596 * Setup value stack: clamp to 'nargs', fill up to 'nregs'
57597 */
57598
57599 duk__adjust_valstack_and_top(thr,
57600 num_stack_args,
57601 idx_args,
57602 nregs,
57603 nargs,
57604 func);
57605
57606 /*
57607 * Shift to new valstack_bottom.
57608 */
57609
57610 thr->valstack_bottom = thr->valstack_bottom + idx_args;
57611 /* keep current valstack_top */
57612 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
57613 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
57614 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
57615
57616 /*
57617 * Return to bytecode executor, which will resume execution from
57618 * the topmost activation.
57619 */
57620
57621 return 1;
57622}
7c673cae
FG
57623/*
57624 * Ecmascript compiler.
57625 *
57626 * Parses an input string and generates a function template result.
57627 * Compilation may happen in multiple contexts (global code, eval
57628 * code, function code).
57629 *
57630 * The parser uses a traditional top-down recursive parsing for the
57631 * statement level, and an operator precedence based top-down approach
57632 * for the expression level. The attempt is to minimize the C stack
57633 * depth. Bytecode is generated directly without an intermediate
57634 * representation (tree), at the cost of needing two passes over each
57635 * function.
57636 *
57637 * The top-down recursive parser functions are named "duk__parse_XXX".
57638 *
57639 * Recursion limits are in key functions to prevent arbitrary C recursion:
57640 * function body parsing, statement parsing, and expression parsing.
57641 *
57642 * See doc/compiler.rst for discussion on the design.
57643 *
57644 * A few typing notes:
57645 *
57646 * - duk_regconst_t: unsigned, no marker value for "none"
57647 * - duk_reg_t: signed, < 0 = none
57648 * - PC values: duk_int_t, negative values used as markers
57649 */
57650
57651/* include removed: duk_internal.h */
57652
57653/* if highest bit of a register number is set, it refers to a constant instead */
57654#define DUK__CONST_MARKER DUK_JS_CONST_MARKER
57655
57656/* for array and object literals */
57657#define DUK__MAX_ARRAY_INIT_VALUES 20
57658#define DUK__MAX_OBJECT_INIT_PAIRS 10
57659
57660/* XXX: hack, remove when const lookup is not O(n) */
57661#define DUK__GETCONST_MAX_CONSTS_CHECK 256
57662
57663/* These limits are based on bytecode limits. Max temps is limited
57664 * by duk_hcompiledfunction nargs/nregs fields being 16 bits.
57665 */
57666#define DUK__MAX_CONSTS DUK_BC_BC_MAX
57667#define DUK__MAX_FUNCS DUK_BC_BC_MAX
57668#define DUK__MAX_TEMPS 0xffffL
57669
57670/* Initial bytecode size allocation. */
57671#define DUK__BC_INITIAL_INSTS 256
57672
57673#define DUK__RECURSION_INCREASE(comp_ctx,thr) do { \
57674 DUK_DDD(DUK_DDDPRINT("RECURSION INCREASE: %s:%ld", (const char *) DUK_FILE_MACRO, (long) DUK_LINE_MACRO)); \
57675 duk__recursion_increase((comp_ctx)); \
57676 } while (0)
57677
57678#define DUK__RECURSION_DECREASE(comp_ctx,thr) do { \
57679 DUK_DDD(DUK_DDDPRINT("RECURSION DECREASE: %s:%ld", (const char *) DUK_FILE_MACRO, (long) DUK_LINE_MACRO)); \
57680 duk__recursion_decrease((comp_ctx)); \
57681 } while (0)
57682
57683/* Value stack slot limits: these are quite approximate right now, and
57684 * because they overlap in control flow, some could be eliminated.
57685 */
57686#define DUK__COMPILE_ENTRY_SLOTS 8
57687#define DUK__FUNCTION_INIT_REQUIRE_SLOTS 16
57688#define DUK__FUNCTION_BODY_REQUIRE_SLOTS 16
57689#define DUK__PARSE_STATEMENTS_SLOTS 16
57690#define DUK__PARSE_EXPR_SLOTS 16
57691
57692/* Temporary structure used to pass a stack allocated region through
57693 * duk_safe_call().
57694 */
57695typedef struct {
57696 duk_small_uint_t flags;
57697 duk_compiler_ctx comp_ctx_alloc;
57698 duk_lexer_point lex_pt_alloc;
57699} duk__compiler_stkstate;
57700
57701/*
57702 * Prototypes
57703 */
57704
57705/* lexing */
57706DUK_LOCAL_DECL void duk__advance_helper(duk_compiler_ctx *comp_ctx, duk_small_int_t expect);
57707DUK_LOCAL_DECL void duk__advance_expect(duk_compiler_ctx *comp_ctx, duk_small_int_t expect);
57708DUK_LOCAL_DECL void duk__advance(duk_compiler_ctx *ctx);
57709
57710/* function helpers */
57711DUK_LOCAL_DECL void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx);
57712DUK_LOCAL_DECL void duk__reset_func_for_pass2(duk_compiler_ctx *comp_ctx);
57713DUK_LOCAL_DECL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ctx, duk_reg_t *out_stmt_value_reg);
57714DUK_LOCAL_DECL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_bool_t force_no_namebind);
57715DUK_LOCAL_DECL duk_int_t duk__cleanup_varmap(duk_compiler_ctx *comp_ctx);
57716
57717/* code emission */
57718DUK_LOCAL_DECL duk_int_t duk__get_current_pc(duk_compiler_ctx *comp_ctx);
57719DUK_LOCAL_DECL duk_compiler_instr *duk__get_instr_ptr(duk_compiler_ctx *comp_ctx, duk_int_t pc);
57720DUK_LOCAL_DECL void duk__emit(duk_compiler_ctx *comp_ctx, duk_instr_t ins);
57721#if 0 /* unused */
57722DUK_LOCAL_DECL void duk__emit_op_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t op);
57723#endif
57724DUK_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);
57725DUK_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);
57726#if 0 /* unused */
57727DUK_LOCAL_DECL void duk__emit_a(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a);
57728#endif
57729DUK_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);
57730DUK_LOCAL_DECL void duk__emit_abc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t abc);
57731DUK_LOCAL_DECL void duk__emit_extraop_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop_flags, duk_regconst_t b, duk_regconst_t c);
57732DUK_LOCAL_DECL void duk__emit_extraop_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop_flags, duk_regconst_t b);
57733DUK_LOCAL_DECL void duk__emit_extraop_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop, duk_regconst_t bc);
57734DUK_LOCAL_DECL void duk__emit_extraop_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop_flags);
57735DUK_LOCAL_DECL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val);
57736DUK_LOCAL_DECL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val);
57737DUK_LOCAL_DECL void duk__emit_jump(duk_compiler_ctx *comp_ctx, duk_int_t target_pc);
57738DUK_LOCAL_DECL duk_int_t duk__emit_jump_empty(duk_compiler_ctx *comp_ctx);
57739DUK_LOCAL_DECL void duk__insert_jump_entry(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc);
57740DUK_LOCAL_DECL void duk__patch_jump(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc, duk_int_t target_pc);
57741DUK_LOCAL_DECL void duk__patch_jump_here(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc);
57742DUK_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);
57743DUK_LOCAL_DECL void duk__emit_if_false_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst);
57744DUK_LOCAL_DECL void duk__emit_if_true_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst);
57745DUK_LOCAL_DECL void duk__emit_invalid(duk_compiler_ctx *comp_ctx);
57746
57747/* ivalue/ispec helpers */
57748DUK_LOCAL_DECL void duk__copy_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *src, duk_ispec *dst);
57749DUK_LOCAL_DECL void duk__copy_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *src, duk_ivalue *dst);
57750DUK_LOCAL_DECL duk_bool_t duk__is_whole_get_int32(duk_double_t x, duk_int32_t *ival);
57751DUK_LOCAL_DECL duk_reg_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_int_t num);
57752DUK_LOCAL_DECL duk_reg_t duk__alloctemp(duk_compiler_ctx *comp_ctx);
57753DUK_LOCAL_DECL void duk__settemp_checkmax(duk_compiler_ctx *comp_ctx, duk_reg_t temp_next);
57754DUK_LOCAL_DECL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx);
57755DUK_LOCAL_DECL
57756duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
57757 duk_ispec *x,
57758 duk_reg_t forced_reg,
57759 duk_small_uint_t flags);
57760DUK_LOCAL_DECL void duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, duk_reg_t forced_reg);
57761DUK_LOCAL_DECL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_reg_t forced_reg);
57762DUK_LOCAL_DECL void duk__ivalue_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
57763DUK_LOCAL_DECL void duk__ivalue_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
57764DUK_LOCAL_DECL
57765duk_regconst_t duk__ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx,
57766 duk_ivalue *x,
57767 duk_reg_t forced_reg,
57768 duk_small_uint_t flags);
57769DUK_LOCAL_DECL duk_reg_t duk__ivalue_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
57770#if 0 /* unused */
11fdf7f2 57771DUK_LOCAL_DECL duk_reg_t duk__ivalue_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
7c673cae
FG
57772#endif
57773DUK_LOCAL_DECL void duk__ivalue_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_int_t forced_reg);
57774DUK_LOCAL_DECL duk_regconst_t duk__ivalue_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
11fdf7f2 57775DUK_LOCAL_DECL duk_regconst_t duk__ivalue_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
7c673cae
FG
57776
57777/* identifier handling */
57778DUK_LOCAL_DECL duk_reg_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_ctx);
57779DUK_LOCAL_DECL duk_bool_t duk__lookup_lhs(duk_compiler_ctx *ctx, duk_reg_t *out_reg_varbind, duk_regconst_t *out_rc_varname);
57780
57781/* label handling */
57782DUK_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);
57783DUK_LOCAL_DECL void duk__update_label_flags(duk_compiler_ctx *comp_ctx, duk_int_t label_id, duk_small_uint_t flags);
57784DUK_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);
57785DUK_LOCAL_DECL void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, duk_int_t len);
57786
57787/* top-down expression parser */
57788DUK_LOCAL_DECL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
57789DUK_LOCAL_DECL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_ivalue *res);
57790DUK_LOCAL_DECL duk_small_uint_t duk__expr_lbp(duk_compiler_ctx *comp_ctx);
57791DUK_LOCAL_DECL duk_bool_t duk__expr_is_empty(duk_compiler_ctx *comp_ctx);
57792
57793/* exprtop is the top level variant which resets nud/led counts */
57794DUK_LOCAL_DECL void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
57795DUK_LOCAL_DECL void duk__exprtop(duk_compiler_ctx *ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
57796
57797/* convenience helpers */
11fdf7f2 57798#if 0 /* unused */
7c673cae 57799DUK_LOCAL_DECL duk_reg_t duk__expr_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
11fdf7f2 57800#endif
7c673cae 57801#if 0 /* unused */
11fdf7f2 57802DUK_LOCAL_DECL duk_reg_t duk__expr_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
7c673cae
FG
57803#endif
57804DUK_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);
57805DUK_LOCAL_DECL duk_regconst_t duk__expr_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
11fdf7f2
TL
57806#if 0 /* unused */
57807DUK_LOCAL_DECL duk_regconst_t duk__expr_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
57808#endif
7c673cae
FG
57809DUK_LOCAL_DECL void duk__expr_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
57810DUK_LOCAL_DECL void duk__expr_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
57811DUK_LOCAL_DECL duk_reg_t duk__exprtop_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
57812#if 0 /* unused */
11fdf7f2 57813DUK_LOCAL_DECL duk_reg_t duk__exprtop_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
7c673cae
FG
57814#endif
57815DUK_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);
57816DUK_LOCAL_DECL duk_regconst_t duk__exprtop_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
57817#if 0 /* unused */
57818DUK_LOCAL_DECL void duk__exprtop_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
57819#endif
57820
57821/* expression parsing helpers */
57822DUK_LOCAL_DECL duk_int_t duk__parse_arguments(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
57823DUK_LOCAL_DECL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
57824DUK_LOCAL_DECL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
57825DUK_LOCAL_DECL duk_bool_t duk__nud_object_literal_key_check(duk_compiler_ctx *comp_ctx, duk_small_uint_t new_key_flags);
57826
57827/* statement parsing */
57828DUK_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);
11fdf7f2 57829DUK_LOCAL_DECL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags);
7c673cae
FG
57830DUK_LOCAL_DECL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site);
57831DUK_LOCAL_DECL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site);
57832DUK_LOCAL_DECL void duk__parse_if_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
57833DUK_LOCAL_DECL void duk__parse_do_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site);
57834DUK_LOCAL_DECL void duk__parse_while_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site);
57835DUK_LOCAL_DECL void duk__parse_break_or_continue_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
57836DUK_LOCAL_DECL void duk__parse_return_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
57837DUK_LOCAL_DECL void duk__parse_throw_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
57838DUK_LOCAL_DECL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
57839DUK_LOCAL_DECL void duk__parse_with_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
57840DUK_LOCAL_DECL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_bool_t allow_source_elem);
57841DUK_LOCAL_DECL duk_int_t duk__stmt_label_site(duk_compiler_ctx *comp_ctx, duk_int_t label_id);
57842DUK_LOCAL_DECL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_source_elem, duk_bool_t expect_eof);
57843
57844DUK_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);
57845DUK_LOCAL_DECL void duk__parse_func_formals(duk_compiler_ctx *comp_ctx);
57846DUK_LOCAL_DECL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_bool_t is_decl, duk_bool_t is_setget);
57847DUK_LOCAL_DECL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_bool_t is_decl, duk_bool_t is_setget);
57848
57849/*
57850 * Parser control values for tokens. The token table is ordered by the
57851 * DUK_TOK_XXX defines.
57852 *
57853 * The binding powers are for lbp() use (i.e. for use in led() context).
57854 * Binding powers are positive for typing convenience, and bits at the
57855 * top should be reserved for flags. Binding power step must be higher
57856 * than 1 so that binding power "lbp - 1" can be used for right associative
57857 * operators. Currently a step of 2 is used (which frees one more bit for
57858 * flags).
57859 */
57860
57861/* XXX: actually single step levels would work just fine, clean up */
57862
57863/* binding power "levels" (see doc/compiler.rst) */
57864#define DUK__BP_INVALID 0 /* always terminates led() */
57865#define DUK__BP_EOF 2
57866#define DUK__BP_CLOSING 4 /* token closes expression, e.g. ')', ']' */
57867#define DUK__BP_FOR_EXPR DUK__BP_CLOSING /* bp to use when parsing a top level Expression */
57868#define DUK__BP_COMMA 6
57869#define DUK__BP_ASSIGNMENT 8
57870#define DUK__BP_CONDITIONAL 10
57871#define DUK__BP_LOR 12
57872#define DUK__BP_LAND 14
57873#define DUK__BP_BOR 16
57874#define DUK__BP_BXOR 18
57875#define DUK__BP_BAND 20
57876#define DUK__BP_EQUALITY 22
57877#define DUK__BP_RELATIONAL 24
57878#define DUK__BP_SHIFT 26
57879#define DUK__BP_ADDITIVE 28
57880#define DUK__BP_MULTIPLICATIVE 30
57881#define DUK__BP_POSTFIX 32
57882#define DUK__BP_CALL 34
57883#define DUK__BP_MEMBER 36
57884
57885#define DUK__TOKEN_LBP_BP_MASK 0x1f
57886#define DUK__TOKEN_LBP_FLAG_NO_REGEXP (1 << 5) /* regexp literal must not follow this token */
57887#define DUK__TOKEN_LBP_FLAG_TERMINATES (1 << 6) /* terminates expression; e.g. post-increment/-decrement */
57888#define DUK__TOKEN_LBP_FLAG_UNUSED (1 << 7) /* spare */
57889
57890#define DUK__TOKEN_LBP_GET_BP(x) ((duk_small_uint_t) (((x) & DUK__TOKEN_LBP_BP_MASK) * 2))
57891
57892#define DUK__MK_LBP(bp) ((bp) >> 1) /* bp is assumed to be even */
57893#define DUK__MK_LBP_FLAGS(bp,flags) (((bp) >> 1) | (flags))
57894
57895DUK_LOCAL const duk_uint8_t duk__token_lbp[] = {
57896 DUK__MK_LBP(DUK__BP_EOF), /* DUK_TOK_EOF */
57897 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_IDENTIFIER */
57898 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_BREAK */
57899 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CASE */
57900 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CATCH */
57901 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CONTINUE */
57902 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_DEBUGGER */
57903 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_DEFAULT */
57904 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_DELETE */
57905 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_DO */
57906 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_ELSE */
57907 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_FINALLY */
57908 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_FOR */
57909 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_FUNCTION */
57910 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_IF */
57911 DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_IN */
57912 DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_INSTANCEOF */
57913 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_NEW */
57914 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_RETURN */
57915 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_SWITCH */
57916 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_THIS */
57917 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_THROW */
57918 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_TRY */
57919 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_TYPEOF */
57920 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_VAR */
11fdf7f2 57921 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CONST */
7c673cae
FG
57922 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_VOID */
57923 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_WHILE */
57924 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_WITH */
57925 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CLASS */
7c673cae
FG
57926 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_ENUM */
57927 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_EXPORT */
57928 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_EXTENDS */
57929 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_IMPORT */
57930 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_SUPER */
57931 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_NULL */
57932 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_TRUE */
57933 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_FALSE */
57934 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_GET */
57935 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_SET */
57936 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_IMPLEMENTS */
57937 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_INTERFACE */
57938 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_LET */
57939 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_PACKAGE */
57940 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_PRIVATE */
57941 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_PROTECTED */
57942 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_PUBLIC */
57943 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_STATIC */
57944 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_YIELD */
57945 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_LCURLY */
57946 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_RCURLY */
57947 DUK__MK_LBP(DUK__BP_MEMBER), /* DUK_TOK_LBRACKET */
57948 DUK__MK_LBP_FLAGS(DUK__BP_CLOSING, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_RBRACKET */
57949 DUK__MK_LBP(DUK__BP_CALL), /* DUK_TOK_LPAREN */
57950 DUK__MK_LBP_FLAGS(DUK__BP_CLOSING, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_RPAREN */
57951 DUK__MK_LBP(DUK__BP_MEMBER), /* DUK_TOK_PERIOD */
57952 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_SEMICOLON */
57953 DUK__MK_LBP(DUK__BP_COMMA), /* DUK_TOK_COMMA */
57954 DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_LT */
57955 DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_GT */
57956 DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_LE */
57957 DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_GE */
57958 DUK__MK_LBP(DUK__BP_EQUALITY), /* DUK_TOK_EQ */
57959 DUK__MK_LBP(DUK__BP_EQUALITY), /* DUK_TOK_NEQ */
57960 DUK__MK_LBP(DUK__BP_EQUALITY), /* DUK_TOK_SEQ */
57961 DUK__MK_LBP(DUK__BP_EQUALITY), /* DUK_TOK_SNEQ */
57962 DUK__MK_LBP(DUK__BP_ADDITIVE), /* DUK_TOK_ADD */
57963 DUK__MK_LBP(DUK__BP_ADDITIVE), /* DUK_TOK_SUB */
57964 DUK__MK_LBP(DUK__BP_MULTIPLICATIVE), /* DUK_TOK_MUL */
57965 DUK__MK_LBP(DUK__BP_MULTIPLICATIVE), /* DUK_TOK_DIV */
57966 DUK__MK_LBP(DUK__BP_MULTIPLICATIVE), /* DUK_TOK_MOD */
57967 DUK__MK_LBP(DUK__BP_POSTFIX), /* DUK_TOK_INCREMENT */
57968 DUK__MK_LBP(DUK__BP_POSTFIX), /* DUK_TOK_DECREMENT */
57969 DUK__MK_LBP(DUK__BP_SHIFT), /* DUK_TOK_ALSHIFT */
57970 DUK__MK_LBP(DUK__BP_SHIFT), /* DUK_TOK_ARSHIFT */
57971 DUK__MK_LBP(DUK__BP_SHIFT), /* DUK_TOK_RSHIFT */
57972 DUK__MK_LBP(DUK__BP_BAND), /* DUK_TOK_BAND */
57973 DUK__MK_LBP(DUK__BP_BOR), /* DUK_TOK_BOR */
57974 DUK__MK_LBP(DUK__BP_BXOR), /* DUK_TOK_BXOR */
57975 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_LNOT */
57976 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_BNOT */
57977 DUK__MK_LBP(DUK__BP_LAND), /* DUK_TOK_LAND */
57978 DUK__MK_LBP(DUK__BP_LOR), /* DUK_TOK_LOR */
57979 DUK__MK_LBP(DUK__BP_CONDITIONAL), /* DUK_TOK_QUESTION */
57980 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_COLON */
57981 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_EQUALSIGN */
57982 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_ADD_EQ */
57983 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_SUB_EQ */
57984 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_MUL_EQ */
57985 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_DIV_EQ */
57986 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_MOD_EQ */
57987 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_ALSHIFT_EQ */
57988 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_ARSHIFT_EQ */
57989 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_RSHIFT_EQ */
57990 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_BAND_EQ */
57991 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_BOR_EQ */
57992 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_BXOR_EQ */
57993 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_NUMBER */
57994 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_STRING */
57995 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_REGEXP */
57996};
57997
57998/*
57999 * Misc helpers
58000 */
58001
58002DUK_LOCAL void duk__recursion_increase(duk_compiler_ctx *comp_ctx) {
58003 DUK_ASSERT(comp_ctx != NULL);
58004 DUK_ASSERT(comp_ctx->recursion_depth >= 0);
58005 if (comp_ctx->recursion_depth >= comp_ctx->recursion_limit) {
11fdf7f2 58006 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_COMPILER_RECURSION_LIMIT);
7c673cae
FG
58007 }
58008 comp_ctx->recursion_depth++;
58009}
58010
58011DUK_LOCAL void duk__recursion_decrease(duk_compiler_ctx *comp_ctx) {
58012 DUK_ASSERT(comp_ctx != NULL);
58013 DUK_ASSERT(comp_ctx->recursion_depth > 0);
58014 comp_ctx->recursion_depth--;
58015}
58016
58017DUK_LOCAL duk_bool_t duk__hstring_is_eval_or_arguments(duk_compiler_ctx *comp_ctx, duk_hstring *h) {
58018 DUK_UNREF(comp_ctx);
58019 DUK_ASSERT(h != NULL);
58020 return DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(h);
58021}
58022
58023DUK_LOCAL duk_bool_t duk__hstring_is_eval_or_arguments_in_strict_mode(duk_compiler_ctx *comp_ctx, duk_hstring *h) {
58024 DUK_ASSERT(h != NULL);
58025 return (comp_ctx->curr_func.is_strict &&
58026 DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(h));
58027}
58028
58029/*
58030 * Parser duk__advance() token eating functions
58031 */
58032
58033/* XXX: valstack handling is awkward. Add a valstack helper which
58034 * avoids dup():ing; valstack_copy(src, dst)?
58035 */
58036
58037DUK_LOCAL void duk__advance_helper(duk_compiler_ctx *comp_ctx, duk_small_int_t expect) {
58038 duk_hthread *thr = comp_ctx->thr;
58039 duk_context *ctx = (duk_context *) thr;
58040 duk_bool_t regexp;
58041
58042 DUK_ASSERT(comp_ctx->curr_token.t >= 0 && comp_ctx->curr_token.t <= DUK_TOK_MAXVAL); /* MAXVAL is inclusive */
58043
58044 /*
58045 * Use current token to decide whether a RegExp can follow.
58046 *
58047 * We can use either 't' or 't_nores'; the latter would not
58048 * recognize keywords. Some keywords can be followed by a
58049 * RegExp (e.g. "return"), so using 't' is better. This is
58050 * not trivial, see doc/compiler.rst.
58051 */
58052
58053 regexp = 1;
58054 if (duk__token_lbp[comp_ctx->curr_token.t] & DUK__TOKEN_LBP_FLAG_NO_REGEXP) {
58055 regexp = 0;
58056 }
58057 if (comp_ctx->curr_func.reject_regexp_in_adv) {
58058 comp_ctx->curr_func.reject_regexp_in_adv = 0;
58059 regexp = 0;
58060 }
58061
58062 if (expect >= 0 && comp_ctx->curr_token.t != expect) {
58063 DUK_D(DUK_DPRINT("parse error: expect=%ld, got=%ld",
58064 (long) expect, (long) comp_ctx->curr_token.t));
11fdf7f2 58065 DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR);
7c673cae
FG
58066 }
58067
58068 /* make current token the previous; need to fiddle with valstack "backing store" */
58069 DUK_MEMCPY(&comp_ctx->prev_token, &comp_ctx->curr_token, sizeof(duk_token));
58070 duk_copy(ctx, comp_ctx->tok11_idx, comp_ctx->tok21_idx);
58071 duk_copy(ctx, comp_ctx->tok12_idx, comp_ctx->tok22_idx);
58072
58073 /* parse new token */
58074 duk_lexer_parse_js_input_element(&comp_ctx->lex,
58075 &comp_ctx->curr_token,
58076 comp_ctx->curr_func.is_strict,
58077 regexp);
58078
58079 DUK_DDD(DUK_DDDPRINT("advance: curr: tok=%ld/%ld,%ld,term=%ld,%!T,%!T "
58080 "prev: tok=%ld/%ld,%ld,term=%ld,%!T,%!T",
58081 (long) comp_ctx->curr_token.t,
58082 (long) comp_ctx->curr_token.t_nores,
58083 (long) comp_ctx->curr_token.start_line,
58084 (long) comp_ctx->curr_token.lineterm,
58085 (duk_tval *) duk_get_tval(ctx, comp_ctx->tok11_idx),
58086 (duk_tval *) duk_get_tval(ctx, comp_ctx->tok12_idx),
58087 (long) comp_ctx->prev_token.t,
58088 (long) comp_ctx->prev_token.t_nores,
58089 (long) comp_ctx->prev_token.start_line,
58090 (long) comp_ctx->prev_token.lineterm,
58091 (duk_tval *) duk_get_tval(ctx, comp_ctx->tok21_idx),
58092 (duk_tval *) duk_get_tval(ctx, comp_ctx->tok22_idx)));
58093}
58094
58095/* advance, expecting current token to be a specific token; parse next token in regexp context */
58096DUK_LOCAL void duk__advance_expect(duk_compiler_ctx *comp_ctx, duk_small_int_t expect) {
58097 duk__advance_helper(comp_ctx, expect);
58098}
58099
58100/* advance, whatever the current token is; parse next token in regexp context */
58101DUK_LOCAL void duk__advance(duk_compiler_ctx *comp_ctx) {
58102 duk__advance_helper(comp_ctx, -1);
58103}
58104
58105/*
58106 * Helpers for duk_compiler_func.
58107 */
58108
58109/* init function state: inits valstack allocations */
58110DUK_LOCAL void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx) {
58111 duk_compiler_func *func = &comp_ctx->curr_func;
58112 duk_hthread *thr = comp_ctx->thr;
58113 duk_context *ctx = (duk_context *) thr;
58114 duk_idx_t entry_top;
58115
58116 entry_top = duk_get_top(ctx);
58117
58118 DUK_MEMZERO(func, sizeof(*func)); /* intentional overlap with earlier memzero */
58119#ifdef DUK_USE_EXPLICIT_NULL_INIT
58120 func->h_name = NULL;
58121 func->h_consts = NULL;
58122 func->h_funcs = NULL;
58123 func->h_decls = NULL;
58124 func->h_labelnames = NULL;
58125 func->h_labelinfos = NULL;
58126 func->h_argnames = NULL;
58127 func->h_varmap = NULL;
58128#endif
58129
58130 duk_require_stack(ctx, DUK__FUNCTION_INIT_REQUIRE_SLOTS);
58131
58132 DUK_BW_INIT_PUSHBUF(thr, &func->bw_code, DUK__BC_INITIAL_INSTS * sizeof(duk_compiler_instr));
58133 /* code_idx = entry_top + 0 */
58134
58135 duk_push_array(ctx);
58136 func->consts_idx = entry_top + 1;
11fdf7f2 58137 func->h_consts = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 1);
7c673cae
FG
58138 DUK_ASSERT(func->h_consts != NULL);
58139
58140 duk_push_array(ctx);
58141 func->funcs_idx = entry_top + 2;
11fdf7f2 58142 func->h_funcs = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 2);
7c673cae
FG
58143 DUK_ASSERT(func->h_funcs != NULL);
58144 DUK_ASSERT(func->fnum_next == 0);
58145
58146 duk_push_array(ctx);
58147 func->decls_idx = entry_top + 3;
11fdf7f2 58148 func->h_decls = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 3);
7c673cae
FG
58149 DUK_ASSERT(func->h_decls != NULL);
58150
58151 duk_push_array(ctx);
58152 func->labelnames_idx = entry_top + 4;
11fdf7f2 58153 func->h_labelnames = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 4);
7c673cae
FG
58154 DUK_ASSERT(func->h_labelnames != NULL);
58155
58156 duk_push_dynamic_buffer(ctx, 0);
58157 func->labelinfos_idx = entry_top + 5;
58158 func->h_labelinfos = (duk_hbuffer_dynamic *) duk_get_hbuffer(ctx, entry_top + 5);
58159 DUK_ASSERT(func->h_labelinfos != NULL);
58160 DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(func->h_labelinfos) && !DUK_HBUFFER_HAS_EXTERNAL(func->h_labelinfos));
58161
58162 duk_push_array(ctx);
58163 func->argnames_idx = entry_top + 6;
11fdf7f2 58164 func->h_argnames = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 6);
7c673cae
FG
58165 DUK_ASSERT(func->h_argnames != NULL);
58166
58167 duk_push_object_internal(ctx);
58168 func->varmap_idx = entry_top + 7;
11fdf7f2 58169 func->h_varmap = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 7);
7c673cae
FG
58170 DUK_ASSERT(func->h_varmap != NULL);
58171}
58172
58173/* reset function state (prepare for pass 2) */
58174DUK_LOCAL void duk__reset_func_for_pass2(duk_compiler_ctx *comp_ctx) {
58175 duk_compiler_func *func = &comp_ctx->curr_func;
58176 duk_hthread *thr = comp_ctx->thr;
58177 duk_context *ctx = (duk_context *) thr;
58178
58179 /* reset bytecode buffer but keep current size; pass 2 will
58180 * require same amount or more.
58181 */
58182 DUK_BW_RESET_SIZE(thr, &func->bw_code);
58183
58184 duk_hobject_set_length_zero(thr, func->h_consts);
58185 /* keep func->h_funcs; inner functions are not reparsed to avoid O(depth^2) parsing */
58186 func->fnum_next = 0;
58187 /* duk_hobject_set_length_zero(thr, func->h_funcs); */
58188 duk_hobject_set_length_zero(thr, func->h_labelnames);
58189 duk_hbuffer_reset(thr, func->h_labelinfos);
58190 /* keep func->h_argnames; it is fixed for all passes */
58191
58192 /* truncated in case pass 3 needed */
58193 duk_push_object_internal(ctx);
58194 duk_replace(ctx, func->varmap_idx);
11fdf7f2 58195 func->h_varmap = DUK_GET_HOBJECT_POSIDX(ctx, func->varmap_idx);
7c673cae
FG
58196 DUK_ASSERT(func->h_varmap != NULL);
58197}
58198
58199/* cleanup varmap from any null entries, compact it, etc; returns number
58200 * of final entries after cleanup.
58201 */
58202DUK_LOCAL duk_int_t duk__cleanup_varmap(duk_compiler_ctx *comp_ctx) {
58203 duk_hthread *thr = comp_ctx->thr;
58204 duk_context *ctx = (duk_context *) thr;
58205 duk_hobject *h_varmap;
58206 duk_hstring *h_key;
58207 duk_tval *tv;
58208 duk_uint32_t i, e_next;
58209 duk_int_t ret;
58210
58211 /* [ ... varmap ] */
58212
11fdf7f2 58213 h_varmap = DUK_GET_HOBJECT_NEGIDX(ctx, -1);
7c673cae
FG
58214 DUK_ASSERT(h_varmap != NULL);
58215
58216 ret = 0;
58217 e_next = DUK_HOBJECT_GET_ENEXT(h_varmap);
58218 for (i = 0; i < e_next; i++) {
58219 h_key = DUK_HOBJECT_E_GET_KEY(thr->heap, h_varmap, i);
58220 if (!h_key) {
58221 continue;
58222 }
58223
58224 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, h_varmap, i));
58225
58226 /* The entries can either be register numbers or 'null' values.
58227 * Thus, no need to DECREF them and get side effects. DECREF'ing
58228 * the keys (strings) can cause memory to be freed but no side
58229 * effects as strings don't have finalizers. This is why we can
58230 * rely on the object properties not changing from underneath us.
58231 */
58232
58233 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, h_varmap, i);
58234 if (!DUK_TVAL_IS_NUMBER(tv)) {
58235 DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv));
7c673cae
FG
58236 DUK_HOBJECT_E_SET_KEY(thr->heap, h_varmap, i, NULL);
58237 DUK_HSTRING_DECREF(thr, h_key);
11fdf7f2 58238 /* when key is NULL, value is garbage so no need to set */
7c673cae
FG
58239 } else {
58240 ret++;
58241 }
58242 }
58243
58244 duk_compact(ctx, -1);
58245
58246 return ret;
58247}
58248
58249/* convert duk_compiler_func into a function template, leaving the result
58250 * on top of stack.
58251 */
58252/* XXX: awkward and bloated asm -- use faster internal accesses */
58253DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_bool_t force_no_namebind) {
58254 duk_compiler_func *func = &comp_ctx->curr_func;
58255 duk_hthread *thr = comp_ctx->thr;
58256 duk_context *ctx = (duk_context *) thr;
58257 duk_hcompiledfunction *h_res;
58258 duk_hbuffer_fixed *h_data;
58259 duk_size_t consts_count;
58260 duk_size_t funcs_count;
58261 duk_size_t code_count;
58262 duk_size_t code_size;
58263 duk_size_t data_size;
58264 duk_size_t i;
58265 duk_tval *p_const;
58266 duk_hobject **p_func;
58267 duk_instr_t *p_instr;
58268 duk_compiler_instr *q_instr;
58269 duk_tval *tv;
58270
58271 DUK_DDD(DUK_DDDPRINT("converting duk_compiler_func to function/template"));
58272
58273 /*
58274 * Push result object and init its flags
58275 */
58276
58277 /* Valstack should suffice here, required on function valstack init */
58278
58279 (void) duk_push_compiledfunction(ctx);
11fdf7f2 58280 h_res = (duk_hcompiledfunction *) DUK_GET_HOBJECT_NEGIDX(ctx, -1); /* XXX: specific getter */
7c673cae
FG
58281 DUK_ASSERT(h_res != NULL);
58282
58283 if (func->is_function) {
58284 DUK_DDD(DUK_DDDPRINT("function -> set NEWENV"));
58285 DUK_HOBJECT_SET_NEWENV((duk_hobject *) h_res);
58286
58287 if (!func->is_arguments_shadowed) {
58288 /* arguments object would be accessible; note that shadowing
58289 * bindings are arguments or function declarations, neither
58290 * of which are deletable, so this is safe.
58291 */
58292
58293 if (func->id_access_arguments || func->may_direct_eval) {
58294 DUK_DDD(DUK_DDDPRINT("function may access 'arguments' object directly or "
58295 "indirectly -> set CREATEARGS"));
58296 DUK_HOBJECT_SET_CREATEARGS((duk_hobject *) h_res);
58297 }
58298 }
58299 } else if (func->is_eval && func->is_strict) {
58300 DUK_DDD(DUK_DDDPRINT("strict eval code -> set NEWENV"));
58301 DUK_HOBJECT_SET_NEWENV((duk_hobject *) h_res);
58302 } else {
58303 /* non-strict eval: env is caller's env or global env (direct vs. indirect call)
58304 * global code: env is is global env
58305 */
58306 DUK_DDD(DUK_DDDPRINT("non-strict eval code or global code -> no NEWENV"));
58307 DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV((duk_hobject *) h_res));
58308 }
58309
58310 if (func->is_function && !func->is_decl && func->h_name != NULL && !force_no_namebind) {
58311 /* Object literal set/get functions have a name (property
58312 * name) but must not have a lexical name binding, see
58313 * test-bug-getset-func-name.js.
58314 */
58315 DUK_DDD(DUK_DDDPRINT("function expression with a name -> set NAMEBINDING"));
58316 DUK_HOBJECT_SET_NAMEBINDING((duk_hobject *) h_res);
58317 }
58318
58319 if (func->is_strict) {
58320 DUK_DDD(DUK_DDDPRINT("function is strict -> set STRICT"));
58321 DUK_HOBJECT_SET_STRICT((duk_hobject *) h_res);
58322 }
58323
58324 if (func->is_notail) {
58325 DUK_DDD(DUK_DDDPRINT("function is notail -> set NOTAIL"));
58326 DUK_HOBJECT_SET_NOTAIL((duk_hobject *) h_res);
58327 }
58328
58329 /*
58330 * Build function fixed size 'data' buffer, which contains bytecode,
58331 * constants, and inner function references.
58332 *
58333 * During the building phase 'data' is reachable but incomplete.
58334 * Only incref's occur during building (no refzero or GC happens),
58335 * so the building process is atomic.
58336 */
58337
58338 consts_count = duk_hobject_get_length(thr, func->h_consts);
58339 funcs_count = duk_hobject_get_length(thr, func->h_funcs) / 3;
58340 code_count = DUK_BW_GET_SIZE(thr, &func->bw_code) / sizeof(duk_compiler_instr);
58341 code_size = code_count * sizeof(duk_instr_t);
58342
58343 data_size = consts_count * sizeof(duk_tval) +
58344 funcs_count * sizeof(duk_hobject *) +
58345 code_size;
58346
58347 DUK_DDD(DUK_DDDPRINT("consts_count=%ld, funcs_count=%ld, code_size=%ld -> "
58348 "data_size=%ld*%ld + %ld*%ld + %ld = %ld",
58349 (long) consts_count, (long) funcs_count, (long) code_size,
58350 (long) consts_count, (long) sizeof(duk_tval),
58351 (long) funcs_count, (long) sizeof(duk_hobject *),
58352 (long) code_size, (long) data_size));
58353
58354 duk_push_fixed_buffer(ctx, data_size);
58355 h_data = (duk_hbuffer_fixed *) duk_get_hbuffer(ctx, -1);
58356 DUK_ASSERT(h_data != NULL);
58357
58358 DUK_HCOMPILEDFUNCTION_SET_DATA(thr->heap, h_res, (duk_hbuffer *) h_data);
58359 DUK_HEAPHDR_INCREF(thr, h_data);
58360
58361 p_const = (duk_tval *) (void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_data);
58362 for (i = 0; i < consts_count; i++) {
58363 DUK_ASSERT(i <= DUK_UARRIDX_MAX); /* const limits */
58364 tv = duk_hobject_find_existing_array_entry_tval_ptr(thr->heap, func->h_consts, (duk_uarridx_t) i);
58365 DUK_ASSERT(tv != NULL);
58366 DUK_TVAL_SET_TVAL(p_const, tv);
58367 p_const++;
58368 DUK_TVAL_INCREF(thr, tv); /* may be a string constant */
58369
58370 DUK_DDD(DUK_DDDPRINT("constant: %!T", (duk_tval *) tv));
58371 }
58372
58373 p_func = (duk_hobject **) p_const;
58374 DUK_HCOMPILEDFUNCTION_SET_FUNCS(thr->heap, h_res, p_func);
58375 for (i = 0; i < funcs_count; i++) {
58376 duk_hobject *h;
58377 DUK_ASSERT(i * 3 <= DUK_UARRIDX_MAX); /* func limits */
58378 tv = duk_hobject_find_existing_array_entry_tval_ptr(thr->heap, func->h_funcs, (duk_uarridx_t) (i * 3));
58379 DUK_ASSERT(tv != NULL);
58380 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
58381 h = DUK_TVAL_GET_OBJECT(tv);
58382 DUK_ASSERT(h != NULL);
58383 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(h));
58384 *p_func++ = h;
58385 DUK_HOBJECT_INCREF(thr, h);
58386
58387 DUK_DDD(DUK_DDDPRINT("inner function: %p -> %!iO",
58388 (void *) h, (duk_heaphdr *) h));
58389 }
58390
58391 p_instr = (duk_instr_t *) p_func;
58392 DUK_HCOMPILEDFUNCTION_SET_BYTECODE(thr->heap, h_res, p_instr);
58393
58394 /* copy bytecode instructions one at a time */
58395 q_instr = (duk_compiler_instr *) (void *) DUK_BW_GET_BASEPTR(thr, &func->bw_code);
58396 for (i = 0; i < code_count; i++) {
58397 p_instr[i] = q_instr[i].ins;
58398 }
58399 /* Note: 'q_instr' is still used below */
58400
58401 DUK_ASSERT((duk_uint8_t *) (p_instr + code_count) == DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_data) + data_size);
58402
58403 duk_pop(ctx); /* 'data' (and everything in it) is reachable through h_res now */
58404
58405 /*
58406 * Init object properties
58407 *
58408 * Properties should be added in decreasing order of access frequency.
58409 * (Not very critical for function templates.)
58410 */
58411
58412 DUK_DDD(DUK_DDDPRINT("init function properties"));
58413
58414 /* [ ... res ] */
58415
58416 /* _Varmap: omitted if function is guaranteed not to do slow path identifier
58417 * accesses or if it would turn out to be empty of actual register mappings
58418 * after a cleanup. When debugging is enabled, we always need the varmap to
58419 * be able to lookup variables at any point.
58420 */
58421#if defined(DUK_USE_DEBUGGER_SUPPORT)
58422 if (1) {
58423#else
58424 if (func->id_access_slow || /* directly uses slow accesses */
58425 func->may_direct_eval || /* may indirectly slow access through a direct eval */
58426 funcs_count > 0) { /* has inner functions which may slow access (XXX: this can be optimized by looking at the inner functions) */
58427#endif
58428 duk_int_t num_used;
58429 duk_dup(ctx, func->varmap_idx);
58430 num_used = duk__cleanup_varmap(comp_ctx);
58431 DUK_DDD(DUK_DDDPRINT("cleaned up varmap: %!T (num_used=%ld)",
58432 (duk_tval *) duk_get_tval(ctx, -1), (long) num_used));
58433
58434 if (num_used > 0) {
58435 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE);
58436 } else {
58437 DUK_DDD(DUK_DDDPRINT("varmap is empty after cleanup -> no need to add"));
58438 duk_pop(ctx);
58439 }
58440 }
58441
58442 /* _Formals: omitted if function is guaranteed not to need a (non-strict) arguments object */
58443 if (1) {
58444 /* XXX: Add a proper condition. If formals list is omitted, recheck
58445 * handling for 'length' in duk_js_push_closure(); it currently relies
58446 * on _Formals being set. Removal may need to be conditional to debugging
58447 * being enabled/disabled too.
58448 */
58449 duk_dup(ctx, func->argnames_idx);
58450 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE);
58451 }
58452
58453 /* name */
58454 if (func->h_name) {
58455 duk_push_hstring(ctx, func->h_name);
58456 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
58457 }
58458
58459 /* _Source */
58460#if defined(DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY)
58461 if (0) {
58462 /* XXX: Currently function source code is not stored, as it is not
58463 * required by the standard. Source code should not be stored by
58464 * default (user should enable it explicitly), and the source should
58465 * probably be compressed with a trivial text compressor; average
58466 * compression of 20-30% is quite easy to achieve even with a trivial
58467 * compressor (RLE + backwards lookup).
58468 *
58469 * Debugging needs source code to be useful: sometimes input code is
58470 * not found in files as it may be generated and then eval()'d, given
58471 * by dynamic C code, etc.
58472 *
58473 * Other issues:
58474 *
58475 * - Need tokenizer indices for start and end to substring
58476 * - Always normalize function declaration part?
58477 * - If we keep _Formals, only need to store body
58478 */
58479
58480 /*
58481 * For global or eval code this is straightforward. For functions
58482 * created with the Function constructor we only get the source for
58483 * the body and must manufacture the "function ..." part.
58484 *
58485 * For instance, for constructed functions (v8):
58486 *
58487 * > a = new Function("foo", "bar", "print(foo)");
58488 * [Function]
58489 * > a.toString()
58490 * 'function anonymous(foo,bar) {\nprint(foo)\n}'
58491 *
58492 * Similarly for e.g. getters (v8):
58493 *
58494 * > x = { get a(foo,bar) { print(foo); } }
58495 * { a: [Getter] }
58496 * > Object.getOwnPropertyDescriptor(x, 'a').get.toString()
58497 * 'function a(foo,bar) { print(foo); }'
58498 */
58499
58500#if 0
58501 duk_push_string(ctx, "XXX");
58502 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_SOURCE, DUK_PROPDESC_FLAGS_NONE);
58503#endif
58504 }
58505#endif /* DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY */
58506
58507 /* _Pc2line */
58508#if defined(DUK_USE_PC2LINE)
58509 if (1) {
58510 /*
58511 * Size-optimized pc->line mapping.
58512 */
58513
58514 DUK_ASSERT(code_count <= DUK_COMPILER_MAX_BYTECODE_LENGTH);
58515 duk_hobject_pc2line_pack(thr, q_instr, (duk_uint_fast32_t) code_count); /* -> pushes fixed buffer */
58516 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_NONE);
58517
58518 /* XXX: if assertions enabled, walk through all valid PCs
58519 * and check line mapping.
58520 */
58521 }
58522#endif /* DUK_USE_PC2LINE */
58523
58524 /* fileName */
58525 if (comp_ctx->h_filename) {
58526 /*
58527 * Source filename (or equivalent), for identifying thrown errors.
58528 */
58529
58530 duk_push_hstring(ctx, comp_ctx->h_filename);
58531 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_NONE);
58532 }
58533
58534 /*
58535 * Init remaining result fields
58536 *
58537 * 'nregs' controls how large a register frame is allocated.
58538 *
58539 * 'nargs' controls how many formal arguments are written to registers:
58540 * r0, ... r(nargs-1). The remaining registers are initialized to
58541 * undefined.
58542 */
58543
58544 DUK_ASSERT(func->temp_max >= 0);
11fdf7f2
TL
58545 h_res->nregs = (duk_uint16_t) func->temp_max;
58546 h_res->nargs = (duk_uint16_t) duk_hobject_get_length(thr, func->h_argnames);
7c673cae
FG
58547 DUK_ASSERT(h_res->nregs >= h_res->nargs); /* pass2 allocation handles this */
58548#if defined(DUK_USE_DEBUGGER_SUPPORT)
58549 h_res->start_line = (duk_uint32_t) func->min_line;
58550 h_res->end_line = (duk_uint32_t) func->max_line;
58551#endif
58552
58553 DUK_DD(DUK_DDPRINT("converted function: %!ixT",
58554 (duk_tval *) duk_get_tval(ctx, -1)));
58555
58556 /*
58557 * Compact the function template.
58558 */
58559
58560 duk_compact(ctx, -1);
58561
58562 /*
58563 * Debug dumping
58564 */
58565
58566#ifdef DUK_USE_DDDPRINT
58567 {
58568 duk_hcompiledfunction *h;
58569 duk_instr_t *p, *p_start, *p_end;
58570
58571 h = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);
58572 p_start = (duk_instr_t *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, h);
58573 p_end = (duk_instr_t *) DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr->heap, h);
58574
58575 p = p_start;
58576 while (p < p_end) {
58577 DUK_DDD(DUK_DDDPRINT("BC %04ld: %!I ; 0x%08lx op=%ld (%!C) a=%ld b=%ld c=%ld",
58578 (long) (p - p_start),
58579 (duk_instr_t) (*p),
58580 (unsigned long) (*p),
58581 (long) DUK_DEC_OP(*p),
58582 (long) DUK_DEC_OP(*p),
58583 (long) DUK_DEC_A(*p),
58584 (long) DUK_DEC_B(*p),
58585 (long) DUK_DEC_C(*p)));
58586 p++;
58587 }
58588 }
58589#endif
58590}
58591
58592/*
58593 * Code emission helpers
58594 *
58595 * Some emission helpers understand the range of target and source reg/const
58596 * values and automatically emit shuffling code if necessary. This is the
58597 * case when the slot in question (A, B, C) is used in the standard way and
58598 * for opcodes the emission helpers explicitly understand (like DUK_OP_CALL).
58599 *
58600 * The standard way is that:
58601 * - slot A is a target register
58602 * - slot B is a source register/constant
58603 * - slot C is a source register/constant
58604 *
58605 * If a slot is used in a non-standard way the caller must indicate this
58606 * somehow. If a slot is used as a target instead of a source (or vice
58607 * versa), this can be indicated with a flag to trigger proper shuffling
58608 * (e.g. DUK__EMIT_FLAG_B_IS_TARGET). If the value in the slot is not
58609 * register/const related at all, the caller must ensure that the raw value
58610 * fits into the corresponding slot so as to not trigger shuffling. The
58611 * caller must set a "no shuffle" flag to ensure compilation fails if
58612 * shuffling were to be triggered because of an internal error.
58613 *
58614 * For slots B and C the raw slot size is 9 bits but one bit is reserved for
58615 * the reg/const indicator. To use the full 9-bit range for a raw value,
58616 * shuffling must be disabled with the DUK__EMIT_FLAG_NO_SHUFFLE_{B,C} flag.
58617 * Shuffling is only done for A, B, and C slots, not the larger BC or ABC slots.
58618 *
58619 * There is call handling specific understanding in the A-B-C emitter to
58620 * convert call setup and call instructions into indirect ones if necessary.
58621 */
58622
58623/* Code emission flags, passed in the 'opcode' field. Opcode + flags
58624 * fit into 16 bits for now, so use duk_small_uint.t.
58625 */
58626#define DUK__EMIT_FLAG_NO_SHUFFLE_A (1 << 8)
58627#define DUK__EMIT_FLAG_NO_SHUFFLE_B (1 << 9)
58628#define DUK__EMIT_FLAG_NO_SHUFFLE_C (1 << 10)
58629#define DUK__EMIT_FLAG_A_IS_SOURCE (1 << 11) /* slot A is a source (default: target) */
58630#define DUK__EMIT_FLAG_B_IS_TARGET (1 << 12) /* slot B is a target (default: source) */
58631#define DUK__EMIT_FLAG_C_IS_TARGET (1 << 13) /* slot C is a target (default: source) */
58632#define DUK__EMIT_FLAG_B_IS_TARGETSOURCE (1 << 14) /* slot B is both a target and a source (used by extraops like DUK_EXTRAOP_INSTOF */
58633#define DUK__EMIT_FLAG_RESERVE_JUMPSLOT (1 << 15) /* reserve a jumpslot after instr before target spilling, used for NEXTENUM */
58634
58635/* XXX: clarify on when and where DUK__CONST_MARKER is allowed */
58636/* XXX: opcode specific assertions on when consts are allowed */
58637
58638/* XXX: macro smaller than call? */
58639DUK_LOCAL duk_int_t duk__get_current_pc(duk_compiler_ctx *comp_ctx) {
58640 duk_compiler_func *func;
58641 func = &comp_ctx->curr_func;
58642 return (duk_int_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &func->bw_code) / sizeof(duk_compiler_instr));
58643}
58644
58645DUK_LOCAL duk_compiler_instr *duk__get_instr_ptr(duk_compiler_ctx *comp_ctx, duk_int_t pc) {
58646 DUK_ASSERT(pc >= 0);
58647 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)));
58648 return ((duk_compiler_instr *) (void *) DUK_BW_GET_BASEPTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code)) + pc;
58649}
58650
58651/* emit instruction; could return PC but that's not needed in the majority
58652 * of cases.
58653 */
58654DUK_LOCAL void duk__emit(duk_compiler_ctx *comp_ctx, duk_instr_t ins) {
58655#if defined(DUK_USE_PC2LINE)
58656 duk_int_t line;
58657#endif
58658 duk_compiler_instr *instr;
58659
58660 DUK_DDD(DUK_DDDPRINT("duk__emit: 0x%08lx curr_token.start_line=%ld prev_token.start_line=%ld pc=%ld --> %!I",
58661 (unsigned long) ins,
58662 (long) comp_ctx->curr_token.start_line,
58663 (long) comp_ctx->prev_token.start_line,
58664 (long) duk__get_current_pc(comp_ctx),
58665 (duk_instr_t) ins));
58666
58667 instr = (duk_compiler_instr *) (void *) DUK_BW_ENSURE_GETPTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, sizeof(duk_compiler_instr));
58668 DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, sizeof(duk_compiler_instr));
58669
58670#if defined(DUK_USE_PC2LINE)
58671 /* The line number tracking is a bit inconsistent right now, which
58672 * affects debugger accuracy. Mostly call sites emit opcodes when
58673 * they have parsed a token (say a terminating semicolon) and called
58674 * duk__advance(). In this case the line number of the previous
58675 * token is the most accurate one (except in prologue where
58676 * prev_token.start_line is 0). This is probably not 100% correct
58677 * right now.
58678 */
58679 /* approximation, close enough */
58680 line = comp_ctx->prev_token.start_line;
58681 if (line == 0) {
58682 line = comp_ctx->curr_token.start_line;
58683 }
58684#endif
58685
58686 instr->ins = ins;
58687#if defined(DUK_USE_PC2LINE)
58688 instr->line = line;
58689#endif
58690#if defined(DUK_USE_DEBUGGER_SUPPORT)
58691 if (line < comp_ctx->curr_func.min_line) {
58692 comp_ctx->curr_func.min_line = line;
58693 }
58694 if (line > comp_ctx->curr_func.max_line) {
58695 comp_ctx->curr_func.max_line = line;
58696 }
58697#endif
58698
58699 /* Limit checks for bytecode byte size and line number. */
58700 if (DUK_UNLIKELY(DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) > DUK_USE_ESBC_MAX_BYTES)) {
58701 goto fail_bc_limit;
58702 }
58703#if defined(DUK_USE_PC2LINE) && defined(DUK_USE_ESBC_LIMITS)
58704#if defined(DUK_USE_BUFLEN16)
58705 /* Buffer length is bounded to 0xffff automatically, avoid compile warning. */
58706 if (DUK_UNLIKELY(line > DUK_USE_ESBC_MAX_LINENUMBER)) {
58707 goto fail_bc_limit;
58708 }
58709#else
58710 if (DUK_UNLIKELY(line > DUK_USE_ESBC_MAX_LINENUMBER)) {
58711 goto fail_bc_limit;
58712 }
58713#endif
58714#endif
58715
58716 return;
58717
58718 fail_bc_limit:
11fdf7f2 58719 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_BYTECODE_LIMIT);
7c673cae
FG
58720}
58721
58722/* Update function min/max line from current token. Needed to improve
58723 * function line range information for debugging, so that e.g. opening
58724 * curly brace is covered by line range even when no opcodes are emitted
58725 * for the line containing the brace.
58726 */
58727DUK_LOCAL void duk__update_lineinfo_currtoken(duk_compiler_ctx *comp_ctx) {
58728#if defined(DUK_USE_DEBUGGER_SUPPORT)
58729 duk_int_t line;
58730
58731 line = comp_ctx->curr_token.start_line;
58732 if (line == 0) {
58733 return;
58734 }
58735 if (line < comp_ctx->curr_func.min_line) {
58736 comp_ctx->curr_func.min_line = line;
58737 }
58738 if (line > comp_ctx->curr_func.max_line) {
58739 comp_ctx->curr_func.max_line = line;
58740 }
58741#else
58742 DUK_UNREF(comp_ctx);
58743#endif
58744}
58745
58746#if 0 /* unused */
58747DUK_LOCAL void duk__emit_op_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t op) {
58748 duk__emit(comp_ctx, DUK_ENC_OP_ABC(op, 0));
58749}
58750#endif
58751
58752/* Important main primitive. */
58753DUK_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) {
58754 duk_instr_t ins = 0;
58755 duk_int_t a_out = -1;
58756 duk_int_t b_out = -1;
58757 duk_int_t c_out = -1;
58758 duk_int_t tmp;
58759
58760 DUK_DDD(DUK_DDDPRINT("emit: op_flags=%04lx, a=%ld, b=%ld, c=%ld",
58761 (unsigned long) op_flags, (long) a, (long) b, (long) c));
58762
58763 /* We could rely on max temp/const checks: if they don't exceed BC
58764 * limit, nothing here can either (just asserts would be enough).
58765 * Currently we check for the limits, which provides additional
58766 * protection against creating invalid bytecode due to compiler
58767 * bugs.
58768 */
58769
58770 DUK_ASSERT_DISABLE((op_flags & 0xff) >= DUK_BC_OP_MIN); /* unsigned */
58771 DUK_ASSERT((op_flags & 0xff) <= DUK_BC_OP_MAX);
58772
58773 /* Input shuffling happens before the actual operation, while output
58774 * shuffling happens afterwards. Output shuffling decisions are still
58775 * made at the same time to reduce branch clutter; output shuffle decisions
58776 * are recorded into X_out variables.
58777 */
58778
58779 /* Slot A */
58780
58781#if defined(DUK_USE_SHUFFLE_TORTURE)
58782 if (a <= DUK_BC_A_MAX && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A)) {
58783#else
58784 if (a <= DUK_BC_A_MAX) {
58785#endif
58786 ;
58787 } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A) {
58788 DUK_D(DUK_DPRINT("out of regs: 'a' (reg) needs shuffling but shuffle prohibited, a: %ld", (long) a));
58789 goto error_outofregs;
58790 } else if (a <= DUK_BC_BC_MAX) {
58791 comp_ctx->curr_func.needs_shuffle = 1;
58792 tmp = comp_ctx->curr_func.shuffle1;
58793 if (op_flags & DUK__EMIT_FLAG_A_IS_SOURCE) {
58794 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, a));
58795 } else {
58796 duk_small_int_t op = op_flags & 0xff;
58797 if (op == DUK_OP_CSVAR || op == DUK_OP_CSREG || op == DUK_OP_CSPROP) {
58798 /* Special handling for call setup instructions. The target
58799 * is expressed indirectly, but there is no output shuffling.
58800 */
58801 DUK_ASSERT((op_flags & DUK__EMIT_FLAG_A_IS_SOURCE) == 0);
58802 duk__emit_load_int32_noshuffle(comp_ctx, tmp, a);
58803 DUK_ASSERT(DUK_OP_CSVARI == DUK_OP_CSVAR + 1);
58804 DUK_ASSERT(DUK_OP_CSREGI == DUK_OP_CSREG + 1);
58805 DUK_ASSERT(DUK_OP_CSPROPI == DUK_OP_CSPROP + 1);
58806 op_flags++; /* indirect opcode follows direct */
58807 } else {
58808 /* Output shuffle needed after main operation */
58809 a_out = a;
58810 }
58811 }
58812 a = tmp;
58813 } else {
58814 DUK_D(DUK_DPRINT("out of regs: 'a' (reg) needs shuffling but does not fit into BC, a: %ld", (long) a));
58815 goto error_outofregs;
58816 }
58817
58818 /* Slot B */
58819
58820 if (b & DUK__CONST_MARKER) {
58821 DUK_ASSERT((op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B) == 0);
58822 DUK_ASSERT((op_flags & DUK__EMIT_FLAG_B_IS_TARGET) == 0);
58823 DUK_ASSERT((op_flags & 0xff) != DUK_OP_CALL);
58824 DUK_ASSERT((op_flags & 0xff) != DUK_OP_NEW);
58825 b = b & ~DUK__CONST_MARKER;
58826#if defined(DUK_USE_SHUFFLE_TORTURE)
58827 if (0) {
58828#else
58829 if (b <= 0xff) {
58830#endif
58831 ins |= DUK_ENC_OP_A_B_C(0, 0, 0x100, 0); /* const flag for B */
58832 } else if (b <= DUK_BC_BC_MAX) {
58833 comp_ctx->curr_func.needs_shuffle = 1;
58834 tmp = comp_ctx->curr_func.shuffle2;
58835 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDCONST, tmp, b));
58836 b = tmp;
58837 } else {
58838 DUK_D(DUK_DPRINT("out of regs: 'b' (const) needs shuffling but does not fit into BC, b: %ld", (long) b));
58839 goto error_outofregs;
58840 }
58841 } else {
58842#if defined(DUK_USE_SHUFFLE_TORTURE)
58843 if (b <= 0xff && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B)) {
58844#else
58845 if (b <= 0xff) {
58846#endif
58847 ;
58848 } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B) {
58849 if (b > DUK_BC_B_MAX) {
58850 /* Note: 0xff != DUK_BC_B_MAX */
58851 DUK_D(DUK_DPRINT("out of regs: 'b' (reg) needs shuffling but shuffle prohibited, b: %ld", (long) b));
58852 goto error_outofregs;
58853 }
58854 } else if (b <= DUK_BC_BC_MAX) {
58855 comp_ctx->curr_func.needs_shuffle = 1;
58856 tmp = comp_ctx->curr_func.shuffle2;
58857 if (op_flags & DUK__EMIT_FLAG_B_IS_TARGET) {
58858 /* Output shuffle needed after main operation */
58859 b_out = b;
58860 }
58861 if (!(op_flags & DUK__EMIT_FLAG_B_IS_TARGET) || (op_flags & DUK__EMIT_FLAG_B_IS_TARGETSOURCE)) {
58862 duk_small_int_t op = op_flags & 0xff;
58863 if (op == DUK_OP_CALL || op == DUK_OP_NEW ||
58864 op == DUK_OP_MPUTOBJ || op == DUK_OP_MPUTARR) {
58865 /* Special handling for CALL/NEW/MPUTOBJ/MPUTARR shuffling.
58866 * For each, slot B identifies the first register of a range
58867 * of registers, so normal shuffling won't work. Instead,
58868 * an indirect version of the opcode is used.
58869 */
58870 DUK_ASSERT((op_flags & DUK__EMIT_FLAG_B_IS_TARGET) == 0);
58871 duk__emit_load_int32_noshuffle(comp_ctx, tmp, b);
58872 DUK_ASSERT(DUK_OP_CALLI == DUK_OP_CALL + 1);
58873 DUK_ASSERT(DUK_OP_NEWI == DUK_OP_NEW + 1);
58874 DUK_ASSERT(DUK_OP_MPUTOBJI == DUK_OP_MPUTOBJ + 1);
58875 DUK_ASSERT(DUK_OP_MPUTARRI == DUK_OP_MPUTARR + 1);
58876 op_flags++; /* indirect opcode follows direct */
58877 } else {
58878 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, b));
58879 }
58880 }
58881 b = tmp;
58882 } else {
58883 DUK_D(DUK_DPRINT("out of regs: 'b' (reg) needs shuffling but does not fit into BC, b: %ld", (long) b));
58884 goto error_outofregs;
58885 }
58886 }
58887
58888 /* Slot C */
58889
58890 if (c & DUK__CONST_MARKER) {
58891 DUK_ASSERT((op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C) == 0);
58892 DUK_ASSERT((op_flags & DUK__EMIT_FLAG_C_IS_TARGET) == 0);
58893 c = c & ~DUK__CONST_MARKER;
58894#if defined(DUK_USE_SHUFFLE_TORTURE)
58895 if (0) {
58896#else
58897 if (c <= 0xff) {
58898#endif
58899 ins |= DUK_ENC_OP_A_B_C(0, 0, 0, 0x100); /* const flag for C */
58900 } else if (c <= DUK_BC_BC_MAX) {
58901 comp_ctx->curr_func.needs_shuffle = 1;
58902 tmp = comp_ctx->curr_func.shuffle3;
58903 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDCONST, tmp, c));
58904 c = tmp;
58905 } else {
58906 DUK_D(DUK_DPRINT("out of regs: 'c' (const) needs shuffling but does not fit into BC, c: %ld", (long) c));
58907 goto error_outofregs;
58908 }
58909 } else {
58910#if defined(DUK_USE_SHUFFLE_TORTURE)
58911 if (c <= 0xff && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C)) {
58912#else
58913 if (c <= 0xff) {
58914#endif
58915 ;
58916 } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C) {
58917 if (c > DUK_BC_C_MAX) {
58918 /* Note: 0xff != DUK_BC_C_MAX */
58919 DUK_D(DUK_DPRINT("out of regs: 'c' (reg) needs shuffling but shuffle prohibited, c: %ld", (long) c));
58920 goto error_outofregs;
58921 }
58922 } else if (c <= DUK_BC_BC_MAX) {
58923 comp_ctx->curr_func.needs_shuffle = 1;
58924 tmp = comp_ctx->curr_func.shuffle3;
58925 if (op_flags & DUK__EMIT_FLAG_C_IS_TARGET) {
58926 /* Output shuffle needed after main operation */
58927 c_out = c;
58928 } else {
58929 duk_small_int_t op = op_flags & 0xff;
58930 if (op == DUK_OP_EXTRA &&
58931 (a == DUK_EXTRAOP_INITGET || a == DUK_EXTRAOP_INITSET)) {
58932 /* Special shuffling for INITGET/INITSET, where slot C
58933 * identifies a register pair and cannot be shuffled
58934 * normally. Use an indirect variant instead.
58935 */
58936 DUK_ASSERT((op_flags & DUK__EMIT_FLAG_C_IS_TARGET) == 0);
58937 duk__emit_load_int32_noshuffle(comp_ctx, tmp, c);
58938 DUK_ASSERT(DUK_EXTRAOP_INITGETI == DUK_EXTRAOP_INITGET + 1);
58939 DUK_ASSERT(DUK_EXTRAOP_INITSETI == DUK_EXTRAOP_INITSET + 1);
58940 a++; /* indirect opcode follows direct */
58941 } else {
58942 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, c));
58943 }
58944 }
58945 c = tmp;
58946 } else {
58947 DUK_D(DUK_DPRINT("out of regs: 'c' (reg) needs shuffling but does not fit into BC, c: %ld", (long) c));
58948 goto error_outofregs;
58949 }
58950 }
58951
58952 /* Main operation */
58953
58954 DUK_ASSERT_DISABLE(a >= DUK_BC_A_MIN); /* unsigned */
58955 DUK_ASSERT(a <= DUK_BC_A_MAX);
58956 DUK_ASSERT_DISABLE(b >= DUK_BC_B_MIN); /* unsigned */
58957 DUK_ASSERT(b <= DUK_BC_B_MAX);
58958 DUK_ASSERT_DISABLE(c >= DUK_BC_C_MIN); /* unsigned */
58959 DUK_ASSERT(c <= DUK_BC_C_MAX);
58960
58961 ins |= DUK_ENC_OP_A_B_C(op_flags & 0xff, a, b, c);
58962 duk__emit(comp_ctx, ins);
58963
58964 /* NEXTENUM needs a jump slot right after the main instruction.
58965 * When the JUMP is taken, output spilling is not needed so this
58966 * workaround is possible. The jump slot PC is exceptionally
58967 * plumbed through comp_ctx to minimize call sites.
58968 */
58969 if (op_flags & DUK__EMIT_FLAG_RESERVE_JUMPSLOT) {
58970 comp_ctx->emit_jumpslot_pc = duk__get_current_pc(comp_ctx);
58971 duk__emit_abc(comp_ctx, DUK_OP_JUMP, 0);
58972 }
58973
58974 /* Output shuffling: only one output register is realistically possible.
58975 *
58976 * (Zero would normally be an OK marker value: if the target register
58977 * was zero, it would never be shuffled. But with DUK_USE_SHUFFLE_TORTURE
58978 * this is no longer true, so use -1 as a marker instead.)
58979 */
58980
58981 if (a_out >= 0) {
58982 DUK_ASSERT(b_out < 0);
58983 DUK_ASSERT(c_out < 0);
58984 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, a, a_out));
58985 } else if (b_out >= 0) {
58986 DUK_ASSERT(a_out < 0);
58987 DUK_ASSERT(c_out < 0);
58988 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, b, b_out));
58989 } else if (c_out >= 0) {
58990 DUK_ASSERT(b_out < 0);
58991 DUK_ASSERT(c_out < 0);
58992 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, c, c_out));
58993 }
58994
58995 return;
58996
58997 error_outofregs:
11fdf7f2 58998 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
7c673cae
FG
58999}
59000
59001DUK_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) {
59002 duk__emit_a_b_c(comp_ctx, op_flags | DUK__EMIT_FLAG_NO_SHUFFLE_C, a, b, 0);
59003}
59004
59005#if 0 /* unused */
59006DUK_LOCAL void duk__emit_a(duk_compiler_ctx *comp_ctx, int op_flags, int a) {
59007 duk__emit_a_b_c(comp_ctx, op_flags | DUK__EMIT_FLAG_NO_SHUFFLE_B | DUK__EMIT_FLAG_NO_SHUFFLE_C, a, 0, 0);
59008}
59009#endif
59010
59011DUK_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) {
59012 duk_instr_t ins;
59013 duk_int_t tmp;
59014
59015 /* allow caller to give a const number with the DUK__CONST_MARKER */
59016 bc = bc & (~DUK__CONST_MARKER);
59017
59018 DUK_ASSERT_DISABLE((op_flags & 0xff) >= DUK_BC_OP_MIN); /* unsigned */
59019 DUK_ASSERT((op_flags & 0xff) <= DUK_BC_OP_MAX);
59020 DUK_ASSERT_DISABLE(bc >= DUK_BC_BC_MIN); /* unsigned */
59021 DUK_ASSERT(bc <= DUK_BC_BC_MAX);
59022 DUK_ASSERT((bc & DUK__CONST_MARKER) == 0);
59023
59024 if (bc <= DUK_BC_BC_MAX) {
59025 ;
59026 } else {
59027 /* No BC shuffling now. */
59028 goto error_outofregs;
59029 }
59030
59031#if defined(DUK_USE_SHUFFLE_TORTURE)
59032 if (a <= DUK_BC_A_MAX && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A)) {
59033#else
59034 if (a <= DUK_BC_A_MAX) {
59035#endif
59036 ins = DUK_ENC_OP_A_BC(op_flags & 0xff, a, bc);
59037 duk__emit(comp_ctx, ins);
59038 } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A) {
59039 goto error_outofregs;
59040 } else if (a <= DUK_BC_BC_MAX) {
59041 comp_ctx->curr_func.needs_shuffle = 1;
59042 tmp = comp_ctx->curr_func.shuffle1;
59043 ins = DUK_ENC_OP_A_BC(op_flags & 0xff, tmp, bc);
59044 if (op_flags & DUK__EMIT_FLAG_A_IS_SOURCE) {
59045 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, a));
59046 duk__emit(comp_ctx, ins);
59047 } else {
59048 duk__emit(comp_ctx, ins);
59049 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, tmp, a));
59050 }
59051 } else {
59052 goto error_outofregs;
59053 }
59054 return;
59055
59056 error_outofregs:
11fdf7f2 59057 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
7c673cae
FG
59058}
59059
59060DUK_LOCAL void duk__emit_abc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t abc) {
59061 duk_instr_t ins;
59062
59063 DUK_ASSERT_DISABLE(op >= DUK_BC_OP_MIN); /* unsigned */
59064 DUK_ASSERT(op <= DUK_BC_OP_MAX);
59065 DUK_ASSERT_DISABLE(abc >= DUK_BC_ABC_MIN); /* unsigned */
59066 DUK_ASSERT(abc <= DUK_BC_ABC_MAX);
59067 DUK_ASSERT((abc & DUK__CONST_MARKER) == 0);
59068
59069 if (abc <= DUK_BC_ABC_MAX) {
59070 ;
59071 } else {
59072 goto error_outofregs;
59073 }
59074 ins = DUK_ENC_OP_ABC(op, abc);
59075 DUK_DDD(DUK_DDDPRINT("duk__emit_abc: 0x%08lx line=%ld pc=%ld op=%ld (%!C) abc=%ld (%!I)",
59076 (unsigned long) ins, (long) comp_ctx->curr_token.start_line,
59077 (long) duk__get_current_pc(comp_ctx), (long) op, (long) op,
59078 (long) abc, (duk_instr_t) ins));
59079 duk__emit(comp_ctx, ins);
59080 return;
59081
59082 error_outofregs:
11fdf7f2 59083 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
7c673cae
FG
59084}
59085
59086DUK_LOCAL void duk__emit_extraop_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop_flags, duk_regconst_t b, duk_regconst_t c) {
59087 DUK_ASSERT_DISABLE((extraop_flags & 0xff) >= DUK_BC_EXTRAOP_MIN); /* unsigned */
59088 DUK_ASSERT((extraop_flags & 0xff) <= DUK_BC_EXTRAOP_MAX);
59089 /* Setting "no shuffle A" is covered by the assert, but it's needed
59090 * with DUK_USE_SHUFFLE_TORTURE.
59091 */
59092 duk__emit_a_b_c(comp_ctx,
59093 DUK_OP_EXTRA | DUK__EMIT_FLAG_NO_SHUFFLE_A | (extraop_flags & ~0xff), /* transfer flags */
59094 extraop_flags & 0xff,
59095 b,
59096 c);
59097}
59098
59099DUK_LOCAL void duk__emit_extraop_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop_flags, duk_regconst_t b) {
59100 DUK_ASSERT_DISABLE((extraop_flags & 0xff) >= DUK_BC_EXTRAOP_MIN); /* unsigned */
59101 DUK_ASSERT((extraop_flags & 0xff) <= DUK_BC_EXTRAOP_MAX);
59102 /* Setting "no shuffle A" is covered by the assert, but it's needed
59103 * with DUK_USE_SHUFFLE_TORTURE.
59104 */
59105 duk__emit_a_b_c(comp_ctx,
59106 DUK_OP_EXTRA | DUK__EMIT_FLAG_NO_SHUFFLE_A | (extraop_flags & ~0xff), /* transfer flags */
59107 extraop_flags & 0xff,
59108 b,
59109 0);
59110}
59111
59112DUK_LOCAL void duk__emit_extraop_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop, duk_regconst_t bc) {
59113 DUK_ASSERT_DISABLE(extraop >= DUK_BC_EXTRAOP_MIN); /* unsigned */
59114 DUK_ASSERT(extraop <= DUK_BC_EXTRAOP_MAX);
59115 /* Setting "no shuffle A" is covered by the assert, but it's needed
59116 * with DUK_USE_SHUFFLE_TORTURE.
59117 */
59118 duk__emit_a_bc(comp_ctx,
59119 DUK_OP_EXTRA | DUK__EMIT_FLAG_NO_SHUFFLE_A,
59120 extraop,
59121 bc);
59122}
59123
59124DUK_LOCAL void duk__emit_extraop_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop_flags) {
59125 DUK_ASSERT_DISABLE((extraop_flags & 0xff) >= DUK_BC_EXTRAOP_MIN); /* unsigned */
59126 DUK_ASSERT((extraop_flags & 0xff) <= DUK_BC_EXTRAOP_MAX);
59127 /* Setting "no shuffle A" is covered by the assert, but it's needed
59128 * with DUK_USE_SHUFFLE_TORTURE.
59129 */
59130 duk__emit_a_b_c(comp_ctx,
59131 DUK_OP_EXTRA | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_B |
59132 DUK__EMIT_FLAG_NO_SHUFFLE_C | (extraop_flags & ~0xff), /* transfer flags */
59133 extraop_flags & 0xff,
59134 0,
59135 0);
59136}
59137
59138DUK_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) {
59139 /* XXX: Shuffling support could be implemented here so that LDINT+LDINTX
59140 * would only shuffle once (instead of twice). The current code works
59141 * though, and has a smaller compiler footprint.
59142 */
59143
59144 if ((val >= (duk_int32_t) DUK_BC_BC_MIN - (duk_int32_t) DUK_BC_LDINT_BIAS) &&
59145 (val <= (duk_int32_t) DUK_BC_BC_MAX - (duk_int32_t) DUK_BC_LDINT_BIAS)) {
59146 DUK_DDD(DUK_DDDPRINT("emit LDINT to reg %ld for %ld", (long) reg, (long) val));
59147 duk__emit_a_bc(comp_ctx, DUK_OP_LDINT | op_flags, reg, (duk_regconst_t) (val + (duk_int32_t) DUK_BC_LDINT_BIAS));
59148 } else {
59149 duk_int32_t hi = val >> DUK_BC_LDINTX_SHIFT;
59150 duk_int32_t lo = val & ((((duk_int32_t) 1) << DUK_BC_LDINTX_SHIFT) - 1);
59151 DUK_ASSERT(lo >= 0);
59152 DUK_DDD(DUK_DDDPRINT("emit LDINT+LDINTX to reg %ld for %ld -> hi %ld, lo %ld",
59153 (long) reg, (long) val, (long) hi, (long) lo));
59154 duk__emit_a_bc(comp_ctx, DUK_OP_LDINT | op_flags, reg, (duk_regconst_t) (hi + (duk_int32_t) DUK_BC_LDINT_BIAS));
59155 duk__emit_a_bc(comp_ctx, DUK_OP_LDINTX | op_flags, reg, (duk_regconst_t) lo);
59156 }
59157}
59158
59159DUK_LOCAL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val) {
59160 duk__emit_load_int32_raw(comp_ctx, reg, val, 0 /*op_flags*/);
59161}
59162
59163#if defined(DUK_USE_SHUFFLE_TORTURE)
59164/* Used by duk__emit*() calls so that we don't shuffle the loadints that
59165 * are needed to handle indirect opcodes.
59166 */
59167DUK_LOCAL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val) {
59168 duk__emit_load_int32_raw(comp_ctx, reg, val, DUK__EMIT_FLAG_NO_SHUFFLE_A /*op_flags*/);
59169}
59170#else
59171DUK_LOCAL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val) {
59172 /* When torture not enabled, can just use the same helper because
59173 * 'reg' won't get spilled.
59174 */
59175 DUK_ASSERT(reg <= DUK_BC_A_MAX);
59176 duk__emit_load_int32(comp_ctx, reg, val);
59177}
59178#endif
59179
59180DUK_LOCAL void duk__emit_jump(duk_compiler_ctx *comp_ctx, duk_int_t target_pc) {
59181 duk_int_t curr_pc;
59182 duk_int_t offset;
59183
59184 curr_pc = (duk_int_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) / sizeof(duk_compiler_instr));
59185 offset = (duk_int_t) target_pc - (duk_int_t) curr_pc - 1;
59186 DUK_ASSERT(offset + DUK_BC_JUMP_BIAS >= DUK_BC_ABC_MIN);
59187 DUK_ASSERT(offset + DUK_BC_JUMP_BIAS <= DUK_BC_ABC_MAX);
59188 duk__emit_abc(comp_ctx, DUK_OP_JUMP, (duk_regconst_t) (offset + DUK_BC_JUMP_BIAS));
59189}
59190
59191DUK_LOCAL duk_int_t duk__emit_jump_empty(duk_compiler_ctx *comp_ctx) {
59192 duk_int_t ret;
59193
59194 ret = duk__get_current_pc(comp_ctx); /* useful for patching jumps later */
59195 duk__emit_abc(comp_ctx, DUK_OP_JUMP, 0);
59196 return ret;
59197}
59198
59199/* Insert an empty jump in the middle of code emitted earlier. This is
59200 * currently needed for compiling for-in.
59201 */
59202DUK_LOCAL void duk__insert_jump_entry(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc) {
59203#if defined(DUK_USE_PC2LINE)
59204 duk_int_t line;
59205#endif
59206 duk_compiler_instr *instr;
59207 duk_size_t offset;
59208
59209 offset = jump_pc * sizeof(duk_compiler_instr),
59210 instr = (duk_compiler_instr *) (void *)
59211 DUK_BW_INSERT_ENSURE_AREA(comp_ctx->thr,
59212 &comp_ctx->curr_func.bw_code,
59213 offset,
59214 sizeof(duk_compiler_instr));
59215
59216#if defined(DUK_USE_PC2LINE)
59217 line = comp_ctx->curr_token.start_line; /* approximation, close enough */
59218#endif
59219 instr->ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, 0);
59220#if defined(DUK_USE_PC2LINE)
59221 instr->line = line;
59222#endif
59223
59224 DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, sizeof(duk_compiler_instr));
59225 if (DUK_UNLIKELY(DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) > DUK_USE_ESBC_MAX_BYTES)) {
59226 goto fail_bc_limit;
59227 }
59228 return;
59229
59230 fail_bc_limit:
11fdf7f2 59231 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_BYTECODE_LIMIT);
7c673cae
FG
59232}
59233
59234/* Does not assume that jump_pc contains a DUK_OP_JUMP previously; this is intentional
59235 * to allow e.g. an INVALID opcode be overwritten with a JUMP (label management uses this).
59236 */
59237DUK_LOCAL void duk__patch_jump(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc, duk_int_t target_pc) {
59238 duk_compiler_instr *instr;
59239 duk_int_t offset;
59240
59241 /* allow negative PCs, behave as a no-op */
59242 if (jump_pc < 0) {
59243 DUK_DDD(DUK_DDDPRINT("duk__patch_jump(): nop call, jump_pc=%ld (<0), target_pc=%ld",
59244 (long) jump_pc, (long) target_pc));
59245 return;
59246 }
59247 DUK_ASSERT(jump_pc >= 0);
59248
59249 /* XXX: range assert */
59250 instr = duk__get_instr_ptr(comp_ctx, jump_pc);
59251 DUK_ASSERT(instr != NULL);
59252
59253 /* XXX: range assert */
59254 offset = target_pc - jump_pc - 1;
59255
59256 instr->ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, offset + DUK_BC_JUMP_BIAS);
59257 DUK_DDD(DUK_DDDPRINT("duk__patch_jump(): jump_pc=%ld, target_pc=%ld, offset=%ld",
59258 (long) jump_pc, (long) target_pc, (long) offset));
59259}
59260
59261DUK_LOCAL void duk__patch_jump_here(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc) {
59262 duk__patch_jump(comp_ctx, jump_pc, duk__get_current_pc(comp_ctx));
59263}
59264
59265DUK_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) {
59266 duk_compiler_instr *instr;
59267
59268 DUK_ASSERT((reg_catch & DUK__CONST_MARKER) == 0);
59269
59270 instr = duk__get_instr_ptr(comp_ctx, ldconst_pc);
59271 DUK_ASSERT(DUK_DEC_OP(instr->ins) == DUK_OP_LDCONST);
59272 DUK_ASSERT(instr != NULL);
59273 if (const_varname & DUK__CONST_MARKER) {
59274 /* Have a catch variable. */
59275 const_varname = const_varname & (~DUK__CONST_MARKER);
59276 if (reg_catch > DUK_BC_BC_MAX || const_varname > DUK_BC_BC_MAX) {
59277 /* Catch attempts to use out-of-range reg/const. Without this
59278 * check Duktape 0.12.0 could generate invalid code which caused
59279 * an assert failure on execution. This error is triggered e.g.
59280 * for functions with a lot of constants and a try-catch statement.
59281 * Shuffling or opcode semantics change is needed to fix the issue.
59282 * See: test-bug-trycatch-many-constants.js.
59283 */
59284 DUK_D(DUK_DPRINT("failed to patch trycatch: flags=%ld, reg_catch=%ld, const_varname=%ld (0x%08lx)",
59285 (long) flags, (long) reg_catch, (long) const_varname, (long) const_varname));
11fdf7f2 59286 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
7c673cae
FG
59287 }
59288 instr->ins |= DUK_ENC_OP_A_BC(0, 0, const_varname);
59289 } else {
59290 /* No catch variable, e.g. a try-finally; replace LDCONST with
59291 * NOP to avoid a bogus LDCONST.
59292 */
59293 instr->ins = DUK_ENC_OP_A(DUK_OP_EXTRA, DUK_EXTRAOP_NOP);
59294 }
59295
59296 instr = duk__get_instr_ptr(comp_ctx, trycatch_pc);
59297 DUK_ASSERT(instr != NULL);
59298 DUK_ASSERT_DISABLE(flags >= DUK_BC_A_MIN);
59299 DUK_ASSERT(flags <= DUK_BC_A_MAX);
59300 instr->ins = DUK_ENC_OP_A_BC(DUK_OP_TRYCATCH, flags, reg_catch);
59301}
59302
59303DUK_LOCAL void duk__emit_if_false_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst) {
59304 duk__emit_a_b_c(comp_ctx,
59305 DUK_OP_IF | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_C,
59306 0 /*false*/,
59307 regconst,
59308 0 /*unused*/);
59309}
59310
59311DUK_LOCAL void duk__emit_if_true_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst) {
59312 duk__emit_a_b_c(comp_ctx,
59313 DUK_OP_IF | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_C,
59314 1 /*true*/,
59315 regconst,
59316 0 /*unused*/);
59317}
59318
59319DUK_LOCAL void duk__emit_invalid(duk_compiler_ctx *comp_ctx) {
59320 duk__emit_extraop_bc(comp_ctx, DUK_EXTRAOP_INVALID, 0);
59321}
59322
59323/*
59324 * Peephole optimizer for finished bytecode.
59325 *
59326 * Does not remove opcodes; currently only straightens out unconditional
59327 * jump chains which are generated by several control structures.
59328 */
59329
59330DUK_LOCAL void duk__peephole_optimize_bytecode(duk_compiler_ctx *comp_ctx) {
59331 duk_compiler_instr *bc;
59332 duk_small_uint_t iter;
59333 duk_int_t i, n;
59334 duk_int_t count_opt;
59335
59336 bc = (duk_compiler_instr *) (void *) DUK_BW_GET_BASEPTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code);
59337#if defined(DUK_USE_BUFLEN16)
59338 /* No need to assert, buffer size maximum is 0xffff. */
59339#else
59340 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 */
59341#endif
59342 n = (duk_int_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) / sizeof(duk_compiler_instr));
59343
59344 for (iter = 0; iter < DUK_COMPILER_PEEPHOLE_MAXITER; iter++) {
59345 count_opt = 0;
59346
59347 for (i = 0; i < n; i++) {
59348 duk_instr_t ins;
59349 duk_int_t target_pc1;
59350 duk_int_t target_pc2;
59351
59352 ins = bc[i].ins;
59353 if (DUK_DEC_OP(ins) != DUK_OP_JUMP) {
59354 continue;
59355 }
59356
59357 target_pc1 = i + 1 + DUK_DEC_ABC(ins) - DUK_BC_JUMP_BIAS;
59358 DUK_DDD(DUK_DDDPRINT("consider jump at pc %ld; target_pc=%ld", (long) i, (long) target_pc1));
59359 DUK_ASSERT(target_pc1 >= 0);
59360 DUK_ASSERT(target_pc1 < n);
59361
59362 /* Note: if target_pc1 == i, we'll optimize a jump to itself.
59363 * This does not need to be checked for explicitly; the case
59364 * is rare and max iter breaks us out.
59365 */
59366
59367 ins = bc[target_pc1].ins;
59368 if (DUK_DEC_OP(ins) != DUK_OP_JUMP) {
59369 continue;
59370 }
59371
59372 target_pc2 = target_pc1 + 1 + DUK_DEC_ABC(ins) - DUK_BC_JUMP_BIAS;
59373
59374 DUK_DDD(DUK_DDDPRINT("optimizing jump at pc %ld; old target is %ld -> new target is %ld",
59375 (long) i, (long) target_pc1, (long) target_pc2));
59376
59377 bc[i].ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, target_pc2 - (i + 1) + DUK_BC_JUMP_BIAS);
59378
59379 count_opt++;
59380 }
59381
59382 DUK_DD(DUK_DDPRINT("optimized %ld jumps on peephole round %ld", (long) count_opt, (long) (iter + 1)));
59383
59384 if (count_opt == 0) {
59385 break;
59386 }
59387 }
59388}
59389
59390/*
59391 * Intermediate value helpers
59392 */
59393
59394#define DUK__ISREG(comp_ctx,x) (((x) & DUK__CONST_MARKER) == 0)
59395#define DUK__ISCONST(comp_ctx,x) (((x) & DUK__CONST_MARKER) != 0)
59396#define DUK__ISTEMP(comp_ctx,x) (DUK__ISREG((comp_ctx), (x)) && (duk_regconst_t) (x) >= (duk_regconst_t) ((comp_ctx)->curr_func.temp_first))
59397#define DUK__GETTEMP(comp_ctx) ((comp_ctx)->curr_func.temp_next)
59398#define DUK__SETTEMP(comp_ctx,x) ((comp_ctx)->curr_func.temp_next = (x)) /* dangerous: must only lower (temp_max not updated) */
59399#define DUK__SETTEMP_CHECKMAX(comp_ctx,x) duk__settemp_checkmax((comp_ctx),(x))
59400#define DUK__ALLOCTEMP(comp_ctx) duk__alloctemp((comp_ctx))
59401#define DUK__ALLOCTEMPS(comp_ctx,count) duk__alloctemps((comp_ctx),(count))
59402
59403/* Flags for intermediate value coercions. A flag for using a forced reg
59404 * is not needed, the forced_reg argument suffices and generates better
59405 * code (it is checked as it is used).
59406 */
59407#define DUK__IVAL_FLAG_ALLOW_CONST (1 << 0) /* allow a constant to be returned */
11fdf7f2 59408#define DUK__IVAL_FLAG_REQUIRE_TEMP (1 << 1) /* require a (mutable) temporary as a result (or a const if allowed) */
7c673cae
FG
59409#define DUK__IVAL_FLAG_REQUIRE_SHORT (1 << 2) /* require a short (8-bit) reg/const which fits into bytecode B/C slot */
59410
59411/* XXX: some code might benefit from DUK__SETTEMP_IFTEMP(ctx,x) */
59412
11fdf7f2
TL
59413#if 0 /* enable manually for dumping */
59414#define DUK__DUMP_ISPEC(compctx,ispec) do { duk__dump_ispec((compctx), (ispec)); } while (0)
59415#define DUK__DUMP_IVALUE(compctx,ivalue) do { duk__dump_ivalue((compctx), (ivalue)); } while (0)
59416
59417DUK_LOCAL void duk__dump_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *x) {
59418 DUK_D(DUK_DPRINT("ispec dump: t=%ld regconst=0x%08lx, valstack_idx=%ld, value=%!T",
59419 (long) x->t, (unsigned long) x->regconst, (long) x->valstack_idx,
59420 duk_get_tval((duk_context *) comp_ctx->thr, x->valstack_idx)));
59421}
59422DUK_LOCAL void duk__dump_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
59423 DUK_D(DUK_DPRINT("ivalue dump: t=%ld op=%ld "
59424 "x1={t=%ld regconst=0x%08lx valstack_idx=%ld value=%!T} "
59425 "x2={t=%ld regconst=0x%08lx valstack_idx=%ld value=%!T}",
59426 (long) x->t, (long) x->op,
59427 (long) x->x1.t, (unsigned long) x->x1.regconst, (long) x->x1.valstack_idx,
59428 duk_get_tval((duk_context *) comp_ctx->thr, x->x1.valstack_idx),
59429 (long) x->x2.t, (unsigned long) x->x2.regconst, (long) x->x2.valstack_idx,
59430 duk_get_tval((duk_context *) comp_ctx->thr, x->x2.valstack_idx)));
59431}
59432#else
59433#define DUK__DUMP_ISPEC(comp_ctx,x) do {} while (0)
59434#define DUK__DUMP_IVALUE(comp_ctx,x) do {} while (0)
59435#endif
59436
7c673cae
FG
59437DUK_LOCAL void duk__copy_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *src, duk_ispec *dst) {
59438 duk_context *ctx = (duk_context *) comp_ctx->thr;
59439
59440 dst->t = src->t;
59441 dst->regconst = src->regconst;
59442 duk_copy(ctx, src->valstack_idx, dst->valstack_idx);
59443}
59444
59445DUK_LOCAL void duk__copy_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *src, duk_ivalue *dst) {
59446 duk_context *ctx = (duk_context *) comp_ctx->thr;
59447
59448 dst->t = src->t;
59449 dst->op = src->op;
59450 dst->x1.t = src->x1.t;
59451 dst->x1.regconst = src->x1.regconst;
59452 dst->x2.t = src->x2.t;
59453 dst->x2.regconst = src->x2.regconst;
59454 duk_copy(ctx, src->x1.valstack_idx, dst->x1.valstack_idx);
59455 duk_copy(ctx, src->x2.valstack_idx, dst->x2.valstack_idx);
59456}
59457
59458/* XXX: to util */
59459DUK_LOCAL duk_bool_t duk__is_whole_get_int32(duk_double_t x, duk_int32_t *ival) {
59460 duk_small_int_t c;
59461 duk_int32_t t;
59462
59463 c = DUK_FPCLASSIFY(x);
59464 if (c == DUK_FP_NORMAL || (c == DUK_FP_ZERO && !DUK_SIGNBIT(x))) {
59465 /* Don't allow negative zero as it will cause trouble with
59466 * LDINT+LDINTX. But positive zero is OK.
59467 */
59468 t = (duk_int32_t) x;
59469 if ((duk_double_t) t == x) {
59470 *ival = t;
59471 return 1;
59472 }
59473 }
59474
59475 return 0;
59476}
59477
59478DUK_LOCAL duk_reg_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_int_t num) {
59479 duk_reg_t res;
59480
59481 res = comp_ctx->curr_func.temp_next;
59482 comp_ctx->curr_func.temp_next += num;
59483
59484 if (comp_ctx->curr_func.temp_next > DUK__MAX_TEMPS) { /* == DUK__MAX_TEMPS is OK */
11fdf7f2 59485 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_TEMP_LIMIT);
7c673cae
FG
59486 }
59487
59488 /* maintain highest 'used' temporary, needed to figure out nregs of function */
59489 if (comp_ctx->curr_func.temp_next > comp_ctx->curr_func.temp_max) {
59490 comp_ctx->curr_func.temp_max = comp_ctx->curr_func.temp_next;
59491 }
59492
59493 return res;
59494}
59495
59496DUK_LOCAL duk_reg_t duk__alloctemp(duk_compiler_ctx *comp_ctx) {
59497 return duk__alloctemps(comp_ctx, 1);
59498}
59499
59500DUK_LOCAL void duk__settemp_checkmax(duk_compiler_ctx *comp_ctx, duk_reg_t temp_next) {
59501 comp_ctx->curr_func.temp_next = temp_next;
59502 if (temp_next > comp_ctx->curr_func.temp_max) {
59503 comp_ctx->curr_func.temp_max = temp_next;
59504 }
59505}
59506
59507/* get const for value at valstack top */
59508DUK_LOCAL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx) {
59509 duk_hthread *thr = comp_ctx->thr;
59510 duk_context *ctx = (duk_context *) thr;
59511 duk_compiler_func *f = &comp_ctx->curr_func;
59512 duk_tval *tv1;
59513 duk_int_t i, n, n_check;
59514
59515 n = (duk_int_t) duk_get_length(ctx, f->consts_idx);
59516
11fdf7f2 59517 tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1);
7c673cae
FG
59518 DUK_ASSERT(tv1 != NULL);
59519
59520#if defined(DUK_USE_FASTINT)
59521 /* Explicit check for fastint downgrade. */
59522 DUK_TVAL_CHKFAST_INPLACE(tv1);
59523#endif
59524
59525 /* Sanity workaround for handling functions with a large number of
59526 * constants at least somewhat reasonably. Otherwise checking whether
59527 * we already have the constant would grow very slow (as it is O(N^2)).
59528 */
59529 n_check = (n > DUK__GETCONST_MAX_CONSTS_CHECK ? DUK__GETCONST_MAX_CONSTS_CHECK : n);
59530 for (i = 0; i < n_check; i++) {
59531 duk_tval *tv2 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, f->h_consts, i);
59532
59533 /* Strict equality is NOT enough, because we cannot use the same
59534 * constant for e.g. +0 and -0.
59535 */
59536 if (duk_js_samevalue(tv1, tv2)) {
59537 DUK_DDD(DUK_DDDPRINT("reused existing constant for %!T -> const index %ld",
59538 (duk_tval *) tv1, (long) i));
59539 duk_pop(ctx);
59540 return (duk_regconst_t) (i | DUK__CONST_MARKER);
59541 }
59542 }
59543
59544 if (n > DUK__MAX_CONSTS) {
11fdf7f2 59545 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_CONST_LIMIT);
7c673cae
FG
59546 }
59547
59548 DUK_DDD(DUK_DDDPRINT("allocating new constant for %!T -> const index %ld",
59549 (duk_tval *) tv1, (long) n));
59550 (void) duk_put_prop_index(ctx, f->consts_idx, n); /* invalidates tv1, tv2 */
59551 return (duk_regconst_t) (n | DUK__CONST_MARKER);
59552}
59553
59554/* Get the value represented by an duk_ispec to a register or constant.
59555 * The caller can control the result by indicating whether or not:
59556 *
59557 * (1) a constant is allowed (sometimes the caller needs the result to
59558 * be in a register)
59559 *
59560 * (2) a temporary register is required (usually when caller requires
59561 * the register to be safely mutable; normally either a bound
59562 * register or a temporary register are both OK)
59563 *
59564 * (3) a forced register target needs to be used
59565 *
59566 * Bytecode may be emitted to generate the necessary value. The return
59567 * value is either a register or a constant.
59568 */
59569
59570DUK_LOCAL
59571duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
59572 duk_ispec *x,
59573 duk_reg_t forced_reg,
59574 duk_small_uint_t flags) {
59575 duk_hthread *thr = comp_ctx->thr;
59576 duk_context *ctx = (duk_context *) thr;
59577
59578 DUK_DDD(DUK_DDDPRINT("duk__ispec_toregconst_raw(): x={%ld:%ld:%!T}, "
59579 "forced_reg=%ld, flags 0x%08lx: allow_const=%ld require_temp=%ld require_short=%ld",
59580 (long) x->t,
59581 (long) x->regconst,
59582 (duk_tval *) duk_get_tval(ctx, x->valstack_idx),
59583 (long) forced_reg,
59584 (unsigned long) flags,
59585 (long) ((flags & DUK__IVAL_FLAG_ALLOW_CONST) ? 1 : 0),
59586 (long) ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) ? 1 : 0),
59587 (long) ((flags & DUK__IVAL_FLAG_REQUIRE_SHORT) ? 1 : 0)));
59588
59589 switch (x->t) {
59590 case DUK_ISPEC_VALUE: {
59591 duk_tval *tv;
59592
11fdf7f2 59593 tv = DUK_GET_TVAL_POSIDX(ctx, x->valstack_idx);
7c673cae
FG
59594 DUK_ASSERT(tv != NULL);
59595
59596 switch (DUK_TVAL_GET_TAG(tv)) {
59597 case DUK_TAG_UNDEFINED: {
59598 /* Note: although there is no 'undefined' literal, undefined
59599 * values can occur during compilation as a result of e.g.
59600 * the 'void' operator.
59601 */
59602 duk_reg_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
59603 duk__emit_extraop_bc(comp_ctx, DUK_EXTRAOP_LDUNDEF, (duk_regconst_t) dest);
59604 return (duk_regconst_t) dest;
59605 }
59606 case DUK_TAG_NULL: {
59607 duk_reg_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
59608 duk__emit_extraop_bc(comp_ctx, DUK_EXTRAOP_LDNULL, (duk_regconst_t) dest);
59609 return (duk_regconst_t) dest;
59610 }
59611 case DUK_TAG_BOOLEAN: {
59612 duk_reg_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
59613 duk__emit_extraop_bc(comp_ctx,
59614 (DUK_TVAL_GET_BOOLEAN(tv) ? DUK_EXTRAOP_LDTRUE : DUK_EXTRAOP_LDFALSE),
59615 (duk_regconst_t) dest);
59616 return (duk_regconst_t) dest;
59617 }
59618 case DUK_TAG_POINTER: {
59619 DUK_UNREACHABLE();
59620 break;
59621 }
59622 case DUK_TAG_STRING: {
59623 duk_hstring *h;
59624 duk_reg_t dest;
59625 duk_regconst_t constidx;
59626
59627 h = DUK_TVAL_GET_STRING(tv);
59628 DUK_UNREF(h);
59629 DUK_ASSERT(h != NULL);
59630
59631#if 0 /* XXX: to be implemented? */
59632 /* Use special opcodes to load short strings */
59633 if (DUK_HSTRING_GET_BYTELEN(h) <= 2) {
59634 /* Encode into a single opcode (18 bits can encode 1-2 bytes + length indicator) */
59635 } else if (DUK_HSTRING_GET_BYTELEN(h) <= 6) {
59636 /* Encode into a double constant (53 bits can encode 6*8 = 48 bits + 3-bit length */
59637 }
59638#endif
59639 duk_dup(ctx, x->valstack_idx);
59640 constidx = duk__getconst(comp_ctx);
59641
59642 if (flags & DUK__IVAL_FLAG_ALLOW_CONST) {
59643 return constidx;
59644 }
59645
59646 dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
59647 duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, (duk_regconst_t) dest, constidx);
59648 return (duk_regconst_t) dest;
59649 }
59650 case DUK_TAG_OBJECT: {
59651 DUK_UNREACHABLE();
59652 break;
59653 }
59654 case DUK_TAG_BUFFER: {
59655 DUK_UNREACHABLE();
59656 break;
59657 }
59658 case DUK_TAG_LIGHTFUNC: {
59659 DUK_UNREACHABLE();
59660 break;
59661 }
59662#if defined(DUK_USE_FASTINT)
59663 case DUK_TAG_FASTINT:
59664#endif
59665 default: {
59666 /* number */
59667 duk_reg_t dest;
59668 duk_regconst_t constidx;
59669 duk_double_t dval;
59670 duk_int32_t ival;
59671
11fdf7f2 59672 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
7c673cae
FG
59673 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
59674 dval = DUK_TVAL_GET_NUMBER(tv);
59675
59676 if (!(flags & DUK__IVAL_FLAG_ALLOW_CONST)) {
59677 /* A number can be loaded either through a constant, using
59678 * LDINT, or using LDINT+LDINTX. LDINT is always a size win,
59679 * LDINT+LDINTX is not if the constant is used multiple times.
59680 * Currently always prefer LDINT+LDINTX over a double constant.
59681 */
59682
59683 if (duk__is_whole_get_int32(dval, &ival)) {
59684 dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
59685 duk__emit_load_int32(comp_ctx, dest, ival);
59686 return (duk_regconst_t) dest;
59687 }
59688 }
59689
59690 duk_dup(ctx, x->valstack_idx);
59691 constidx = duk__getconst(comp_ctx);
59692
59693 if (flags & DUK__IVAL_FLAG_ALLOW_CONST) {
59694 return constidx;
59695 } else {
59696 dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
59697 duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, (duk_regconst_t) dest, constidx);
59698 return (duk_regconst_t) dest;
59699 }
59700 }
59701 } /* end switch */
59702 }
59703 case DUK_ISPEC_REGCONST: {
11fdf7f2
TL
59704 if (forced_reg >= 0) {
59705 if (x->regconst & DUK__CONST_MARKER) {
59706 duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, forced_reg, x->regconst);
59707 } else if (x->regconst != (duk_regconst_t) forced_reg) {
59708 duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, forced_reg, x->regconst);
7c673cae 59709 } else {
11fdf7f2
TL
59710 ; /* already in correct reg */
59711 }
59712 return (duk_regconst_t) forced_reg;
59713 }
59714
59715 DUK_ASSERT(forced_reg < 0);
59716 if (x->regconst & DUK__CONST_MARKER) {
59717 if (!(flags & DUK__IVAL_FLAG_ALLOW_CONST)) {
59718 duk_reg_t dest = DUK__ALLOCTEMP(comp_ctx);
59719 duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, (duk_regconst_t) dest, x->regconst);
59720 return (duk_regconst_t) dest;
7c673cae 59721 }
11fdf7f2
TL
59722 return x->regconst;
59723 }
59724
59725 DUK_ASSERT(forced_reg < 0 && !(x->regconst & DUK__CONST_MARKER));
59726 if ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) && !DUK__ISTEMP(comp_ctx, x->regconst)) {
59727 duk_reg_t dest = DUK__ALLOCTEMP(comp_ctx);
59728 duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, (duk_regconst_t) dest, x->regconst);
59729 return (duk_regconst_t) dest;
7c673cae 59730 }
11fdf7f2 59731 return x->regconst;
7c673cae
FG
59732 }
59733 default: {
59734 break;
59735 }
59736 }
59737
11fdf7f2 59738 DUK_ERROR_INTERNAL_DEFMSG(thr);
7c673cae
FG
59739 return 0;
59740}
59741
59742DUK_LOCAL void duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, duk_reg_t forced_reg) {
59743 DUK_ASSERT(forced_reg >= 0);
59744 (void) duk__ispec_toregconst_raw(comp_ctx, x, forced_reg, 0 /*flags*/);
59745}
59746
59747/* Coerce an duk_ivalue to a 'plain' value by generating the necessary
59748 * arithmetic operations, property access, or variable access bytecode.
59749 * The duk_ivalue argument ('x') is converted into a plain value as a
59750 * side effect.
59751 */
59752DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_reg_t forced_reg) {
59753 duk_hthread *thr = comp_ctx->thr;
59754 duk_context *ctx = (duk_context *) thr;
59755
59756 DUK_DDD(DUK_DDDPRINT("duk__ivalue_toplain_raw(): x={t=%ld,op=%ld,x1={%ld:%ld:%!T},x2={%ld:%ld:%!T}}, "
59757 "forced_reg=%ld",
59758 (long) x->t, (long) x->op,
59759 (long) x->x1.t, (long) x->x1.regconst,
59760 (duk_tval *) duk_get_tval(ctx, x->x1.valstack_idx),
59761 (long) x->x2.t, (long) x->x2.regconst,
59762 (duk_tval *) duk_get_tval(ctx, x->x2.valstack_idx),
59763 (long) forced_reg));
59764
59765 switch (x->t) {
59766 case DUK_IVAL_PLAIN: {
59767 return;
59768 }
59769 /* XXX: support unary arithmetic ivalues (useful?) */
59770 case DUK_IVAL_ARITH:
59771 case DUK_IVAL_ARITH_EXTRAOP: {
59772 duk_regconst_t arg1;
59773 duk_regconst_t arg2;
59774 duk_reg_t dest;
59775 duk_tval *tv1;
59776 duk_tval *tv2;
59777
59778 DUK_DDD(DUK_DDDPRINT("arith to plain conversion"));
59779
59780 /* inline arithmetic check for constant values */
59781 /* XXX: use the exactly same arithmetic function here as in executor */
59782 if (x->x1.t == DUK_ISPEC_VALUE && x->x2.t == DUK_ISPEC_VALUE && x->t == DUK_IVAL_ARITH) {
11fdf7f2
TL
59783 tv1 = DUK_GET_TVAL_POSIDX(ctx, x->x1.valstack_idx);
59784 tv2 = DUK_GET_TVAL_POSIDX(ctx, x->x2.valstack_idx);
7c673cae
FG
59785 DUK_ASSERT(tv1 != NULL);
59786 DUK_ASSERT(tv2 != NULL);
59787
59788 DUK_DDD(DUK_DDDPRINT("arith: tv1=%!T, tv2=%!T",
59789 (duk_tval *) tv1,
59790 (duk_tval *) tv2));
59791
59792 if (DUK_TVAL_IS_NUMBER(tv1) && DUK_TVAL_IS_NUMBER(tv2)) {
59793 duk_double_t d1 = DUK_TVAL_GET_NUMBER(tv1);
59794 duk_double_t d2 = DUK_TVAL_GET_NUMBER(tv2);
59795 duk_double_t d3;
59796 duk_bool_t accept = 1;
59797
59798 DUK_DDD(DUK_DDDPRINT("arith inline check: d1=%lf, d2=%lf, op=%ld",
59799 (double) d1, (double) d2, (long) x->op));
59800 switch (x->op) {
59801 case DUK_OP_ADD: d3 = d1 + d2; break;
59802 case DUK_OP_SUB: d3 = d1 - d2; break;
59803 case DUK_OP_MUL: d3 = d1 * d2; break;
59804 case DUK_OP_DIV: d3 = d1 / d2; break;
59805 default: accept = 0; break;
59806 }
59807
59808 if (accept) {
59809 duk_double_union du;
59810 du.d = d3;
59811 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
59812 d3 = du.d;
59813
59814 x->t = DUK_IVAL_PLAIN;
59815 DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE);
59816 DUK_TVAL_SET_NUMBER(tv1, d3); /* old value is number: no refcount */
59817 return;
59818 }
59819 } else if (x->op == DUK_OP_ADD && DUK_TVAL_IS_STRING(tv1) && DUK_TVAL_IS_STRING(tv2)) {
59820 /* inline string concatenation */
59821 duk_dup(ctx, x->x1.valstack_idx);
59822 duk_dup(ctx, x->x2.valstack_idx);
59823 duk_concat(ctx, 2);
59824 duk_replace(ctx, x->x1.valstack_idx);
59825 x->t = DUK_IVAL_PLAIN;
59826 DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE);
59827 return;
59828 }
59829 }
59830
59831 arg1 = duk__ispec_toregconst_raw(comp_ctx, &x->x1, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
59832 arg2 = duk__ispec_toregconst_raw(comp_ctx, &x->x2, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
59833
59834 /* If forced reg, use it as destination. Otherwise try to
59835 * use either coerced ispec if it is a temporary.
59836 *
59837 * When using extraops, avoid reusing arg2 as dest because that
59838 * would lead to an LDREG shuffle below. We still can't guarantee
59839 * dest != arg2 because we may have a forced_reg.
59840 */
59841 if (forced_reg >= 0) {
59842 dest = forced_reg;
59843 } else if (DUK__ISTEMP(comp_ctx, arg1)) {
59844 dest = (duk_reg_t) arg1;
59845 } else if (DUK__ISTEMP(comp_ctx, arg2) && x->t != DUK_IVAL_ARITH_EXTRAOP) {
59846 dest = (duk_reg_t) arg2;
59847 } else {
59848 dest = DUK__ALLOCTEMP(comp_ctx);
59849 }
59850
59851 /* Extraop arithmetic opcodes must have destination same as
59852 * first source. If second source matches destination we need
59853 * a temporary register to avoid clobbering the second source.
59854 *
59855 * XXX: change calling code to avoid this situation in most cases.
59856 */
59857
59858 if (x->t == DUK_IVAL_ARITH_EXTRAOP) {
59859 if (!(DUK__ISREG(comp_ctx, arg1) && (duk_reg_t) arg1 == dest)) {
59860 if (DUK__ISREG(comp_ctx, arg2) && (duk_reg_t) arg2 == dest) {
59861 /* arg2 would be clobbered so reassign it to a temp. */
59862 duk_reg_t tempreg;
59863 tempreg = DUK__ALLOCTEMP(comp_ctx);
59864 duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, tempreg, arg2);
59865 arg2 = tempreg;
59866 }
59867
59868 if (DUK__ISREG(comp_ctx, arg1)) {
59869 duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, dest, arg1);
59870 } else {
59871 DUK_ASSERT(DUK__ISCONST(comp_ctx, arg1));
59872 duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, dest, arg1);
59873 }
59874 }
59875
59876 /* Note: special DUK__EMIT_FLAG_B_IS_TARGETSOURCE
59877 * used to indicate that B is both a source and a
59878 * target register. When shuffled, it needs to be
59879 * both input and output shuffled.
59880 */
59881 DUK_ASSERT(DUK__ISREG(comp_ctx, dest));
59882 duk__emit_extraop_b_c(comp_ctx,
59883 x->op | DUK__EMIT_FLAG_B_IS_TARGET |
59884 DUK__EMIT_FLAG_B_IS_TARGETSOURCE,
59885 (duk_regconst_t) dest,
59886 (duk_regconst_t) arg2);
59887
59888 } else {
59889 DUK_ASSERT(DUK__ISREG(comp_ctx, dest));
59890 duk__emit_a_b_c(comp_ctx, x->op, (duk_regconst_t) dest, arg1, arg2);
59891 }
59892
59893 x->t = DUK_IVAL_PLAIN;
59894 x->x1.t = DUK_ISPEC_REGCONST;
59895 x->x1.regconst = (duk_regconst_t) dest;
59896 return;
59897 }
59898 case DUK_IVAL_PROP: {
59899 /* XXX: very similar to DUK_IVAL_ARITH - merge? */
59900 duk_regconst_t arg1;
59901 duk_regconst_t arg2;
59902 duk_reg_t dest;
59903
59904 /* Need a short reg/const, does not have to be a mutable temp. */
59905 arg1 = duk__ispec_toregconst_raw(comp_ctx, &x->x1, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
59906 arg2 = duk__ispec_toregconst_raw(comp_ctx, &x->x2, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
59907
59908 /* Pick a destination register. If either base value or key
59909 * happens to be a temp value, reuse it as the destination.
59910 *
59911 * XXX: The temp must be a "mutable" one, i.e. such that no
59912 * other expression is using it anymore. Here this should be
59913 * the case because the value of a property access expression
59914 * is neither the base nor the key, but the lookup result.
59915 */
59916
59917 if (forced_reg >= 0) {
59918 dest = forced_reg;
59919 } else if (DUK__ISTEMP(comp_ctx, arg1)) {
59920 dest = (duk_reg_t) arg1;
59921 } else if (DUK__ISTEMP(comp_ctx, arg2)) {
59922 dest = (duk_reg_t) arg2;
59923 } else {
59924 dest = DUK__ALLOCTEMP(comp_ctx);
59925 }
59926
59927 duk__emit_a_b_c(comp_ctx, DUK_OP_GETPROP, (duk_regconst_t) dest, arg1, arg2);
59928
59929 x->t = DUK_IVAL_PLAIN;
59930 x->x1.t = DUK_ISPEC_REGCONST;
59931 x->x1.regconst = (duk_regconst_t) dest;
59932 return;
59933 }
59934 case DUK_IVAL_VAR: {
59935 /* x1 must be a string */
59936 duk_reg_t dest;
59937 duk_reg_t reg_varbind;
59938 duk_regconst_t rc_varname;
59939
59940 DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE);
59941
59942 duk_dup(ctx, x->x1.valstack_idx);
59943 if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
59944 x->t = DUK_IVAL_PLAIN;
59945 x->x1.t = DUK_ISPEC_REGCONST;
59946 x->x1.regconst = (duk_regconst_t) reg_varbind;
59947 } else {
59948 dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
59949 duk__emit_a_bc(comp_ctx, DUK_OP_GETVAR, (duk_regconst_t) dest, rc_varname);
59950 x->t = DUK_IVAL_PLAIN;
59951 x->x1.t = DUK_ISPEC_REGCONST;
59952 x->x1.regconst = (duk_regconst_t) dest;
59953 }
59954 return;
59955 }
59956 case DUK_IVAL_NONE:
59957 default: {
11fdf7f2 59958 DUK_D(DUK_DPRINT("invalid ivalue type: %ld", (long) x->t));
7c673cae
FG
59959 break;
59960 }
59961 }
59962
11fdf7f2 59963 DUK_ERROR_INTERNAL_DEFMSG(thr);
7c673cae
FG
59964 return;
59965}
59966
59967/* evaluate to plain value, no forced register (temp/bound reg both ok) */
59968DUK_LOCAL void duk__ivalue_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
59969 duk__ivalue_toplain_raw(comp_ctx, x, -1 /*forced_reg*/);
59970}
59971
59972/* evaluate to final form (e.g. coerce GETPROP to code), throw away temp */
59973DUK_LOCAL void duk__ivalue_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
59974 duk_reg_t temp;
59975
59976 /* If duk__ivalue_toplain_raw() allocates a temp, forget it and
59977 * restore next temp state.
59978 */
59979 temp = DUK__GETTEMP(comp_ctx);
59980 duk__ivalue_toplain_raw(comp_ctx, x, -1 /*forced_reg*/);
59981 DUK__SETTEMP(comp_ctx, temp);
59982}
59983
59984/* Coerce an duk_ivalue to a register or constant; result register may
59985 * be a temp or a bound register.
59986 *
59987 * The duk_ivalue argument ('x') is converted into a regconst as a
59988 * side effect.
59989 */
59990DUK_LOCAL
59991duk_regconst_t duk__ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx,
59992 duk_ivalue *x,
59993 duk_reg_t forced_reg,
59994 duk_small_uint_t flags) {
59995 duk_hthread *thr = comp_ctx->thr;
59996 duk_context *ctx = (duk_context *) thr;
59997 duk_regconst_t reg;
59998 DUK_UNREF(thr);
59999 DUK_UNREF(ctx);
60000
60001 DUK_DDD(DUK_DDDPRINT("duk__ivalue_toregconst_raw(): x={t=%ld,op=%ld,x1={%ld:%ld:%!T},x2={%ld:%ld:%!T}}, "
60002 "forced_reg=%ld, flags 0x%08lx: allow_const=%ld require_temp=%ld require_short=%ld",
60003 (long) x->t, (long) x->op,
60004 (long) x->x1.t, (long) x->x1.regconst,
60005 (duk_tval *) duk_get_tval(ctx, x->x1.valstack_idx),
60006 (long) x->x2.t, (long) x->x2.regconst,
60007 (duk_tval *) duk_get_tval(ctx, x->x2.valstack_idx),
60008 (long) forced_reg,
60009 (unsigned long) flags,
60010 (long) ((flags & DUK__IVAL_FLAG_ALLOW_CONST) ? 1 : 0),
60011 (long) ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) ? 1 : 0),
60012 (long) ((flags & DUK__IVAL_FLAG_REQUIRE_SHORT) ? 1 : 0)));
60013
60014 /* first coerce to a plain value */
60015 duk__ivalue_toplain_raw(comp_ctx, x, forced_reg);
60016 DUK_ASSERT(x->t == DUK_IVAL_PLAIN);
60017
60018 /* then to a register */
60019 reg = duk__ispec_toregconst_raw(comp_ctx, &x->x1, forced_reg, flags);
60020 x->x1.t = DUK_ISPEC_REGCONST;
60021 x->x1.regconst = reg;
60022
60023 return reg;
60024}
60025
60026DUK_LOCAL duk_reg_t duk__ivalue_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
60027 return duk__ivalue_toregconst_raw(comp_ctx, x, -1, 0 /*flags*/);
60028}
60029
60030#if 0 /* unused */
11fdf7f2 60031DUK_LOCAL duk_reg_t duk__ivalue_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
7c673cae
FG
60032 return duk__ivalue_toregconst_raw(comp_ctx, x, -1, DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
60033}
60034#endif
60035
60036DUK_LOCAL void duk__ivalue_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_int_t forced_reg) {
60037 DUK_ASSERT(forced_reg >= 0);
60038 (void) duk__ivalue_toregconst_raw(comp_ctx, x, forced_reg, 0 /*flags*/);
60039}
60040
60041DUK_LOCAL duk_regconst_t duk__ivalue_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
60042 return duk__ivalue_toregconst_raw(comp_ctx, x, -1, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
60043}
60044
11fdf7f2
TL
60045DUK_LOCAL duk_regconst_t duk__ivalue_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
60046 return duk__ivalue_toregconst_raw(comp_ctx, x, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
60047}
60048
7c673cae
FG
60049/* The issues below can be solved with better flags */
60050
60051/* XXX: many operations actually want toforcedtemp() -- brand new temp? */
60052/* XXX: need a toplain_ignore() which will only coerce a value to a temp
60053 * register if it might have a side effect. Side-effect free values do not
60054 * need to be coerced.
60055 */
60056
60057/*
60058 * Identifier handling
60059 */
60060
60061DUK_LOCAL duk_reg_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_ctx) {
60062 duk_hthread *thr = comp_ctx->thr;
60063 duk_context *ctx = (duk_context *) thr;
60064 duk_hstring *h_varname;
60065 duk_reg_t ret;
60066
60067 DUK_DDD(DUK_DDDPRINT("resolving identifier reference to '%!T'",
60068 (duk_tval *) duk_get_tval(ctx, -1)));
60069
60070 /*
60071 * Special name handling
60072 */
60073
60074 h_varname = duk_get_hstring(ctx, -1);
60075 DUK_ASSERT(h_varname != NULL);
60076
60077 if (h_varname == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)) {
60078 DUK_DDD(DUK_DDDPRINT("flagging function as accessing 'arguments'"));
60079 comp_ctx->curr_func.id_access_arguments = 1;
60080 }
60081
60082 /*
60083 * Inside one or more 'with' statements fall back to slow path always.
60084 * (See e.g. test-stmt-with.js.)
60085 */
60086
60087 if (comp_ctx->curr_func.with_depth > 0) {
60088 DUK_DDD(DUK_DDDPRINT("identifier lookup inside a 'with' -> fall back to slow path"));
60089 goto slow_path;
60090 }
60091
60092 /*
60093 * Any catch bindings ("catch (e)") also affect identifier binding.
60094 *
60095 * Currently, the varmap is modified for the duration of the catch
60096 * clause to ensure any identifier accesses with the catch variable
60097 * name will use slow path.
60098 */
60099
60100 duk_get_prop(ctx, comp_ctx->curr_func.varmap_idx);
60101 if (duk_is_number(ctx, -1)) {
60102 ret = duk_to_int(ctx, -1);
60103 duk_pop(ctx);
60104 } else {
60105 duk_pop(ctx);
60106 goto slow_path;
60107 }
60108
60109 DUK_DDD(DUK_DDDPRINT("identifier lookup -> reg %ld", (long) ret));
60110 return ret;
60111
60112 slow_path:
60113 DUK_DDD(DUK_DDDPRINT("identifier lookup -> slow path"));
60114
60115 comp_ctx->curr_func.id_access_slow = 1;
60116 return (duk_reg_t) -1;
60117}
60118
60119/* Lookup an identifier name in the current varmap, indicating whether the
60120 * identifier is register-bound and if not, allocating a constant for the
60121 * identifier name. Returns 1 if register-bound, 0 otherwise. Caller can
60122 * also check (out_reg_varbind >= 0) to check whether or not identifier is
60123 * register bound. The caller must NOT use out_rc_varname at all unless
60124 * return code is 0 or out_reg_varbind is < 0; this is becuase out_rc_varname
60125 * is unsigned and doesn't have a "unused" / none value.
60126 */
60127DUK_LOCAL duk_bool_t duk__lookup_lhs(duk_compiler_ctx *comp_ctx, duk_reg_t *out_reg_varbind, duk_regconst_t *out_rc_varname) {
60128 duk_hthread *thr = comp_ctx->thr;
60129 duk_context *ctx = (duk_context *) thr;
60130 duk_reg_t reg_varbind;
60131 duk_regconst_t rc_varname;
60132
60133 /* [ ... varname ] */
60134
60135 duk_dup_top(ctx);
60136 reg_varbind = duk__lookup_active_register_binding(comp_ctx);
60137
60138 if (reg_varbind >= 0) {
60139 *out_reg_varbind = reg_varbind;
60140 *out_rc_varname = 0; /* duk_regconst_t is unsigned, so use 0 as dummy value (ignored by caller) */
60141 duk_pop(ctx);
60142 return 1;
60143 } else {
60144 rc_varname = duk__getconst(comp_ctx);
60145 *out_reg_varbind = -1;
60146 *out_rc_varname = rc_varname;
60147 return 0;
60148 }
60149}
60150
60151/*
60152 * Label handling
60153 *
60154 * Labels are initially added with flags prohibiting both break and continue.
60155 * When the statement type is finally uncovered (after potentially multiple
60156 * labels), all the labels are updated to allow/prohibit break and continue.
60157 */
60158
60159DUK_LOCAL void duk__add_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, duk_int_t pc_label, duk_int_t label_id) {
60160 duk_hthread *thr = comp_ctx->thr;
60161 duk_context *ctx = (duk_context *) thr;
60162 duk_size_t n;
60163 duk_size_t new_size;
60164 duk_uint8_t *p;
60165 duk_labelinfo *li_start, *li;
60166
60167 /* Duplicate (shadowing) labels are not allowed, except for the empty
60168 * labels (which are used as default labels for switch and iteration
60169 * statements).
60170 *
60171 * We could also allow shadowing of non-empty pending labels without any
60172 * other issues than breaking the required label shadowing requirements
60173 * of the E5 specification, see Section 12.12.
60174 */
60175
60176 p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, comp_ctx->curr_func.h_labelinfos);
60177 li_start = (duk_labelinfo *) (void *) p;
60178 li = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos));
60179 n = (duk_size_t) (li - li_start);
60180
60181 while (li > li_start) {
60182 li--;
60183
60184 if (li->h_label == h_label && h_label != DUK_HTHREAD_STRING_EMPTY_STRING(thr)) {
11fdf7f2 60185 DUK_ERROR_SYNTAX(thr, DUK_STR_DUPLICATE_LABEL);
7c673cae
FG
60186 }
60187 }
60188
60189 duk_push_hstring(ctx, h_label);
60190 DUK_ASSERT(n <= DUK_UARRIDX_MAX); /* label limits */
60191 (void) duk_put_prop_index(ctx, comp_ctx->curr_func.labelnames_idx, (duk_uarridx_t) n);
60192
60193 new_size = (n + 1) * sizeof(duk_labelinfo);
60194 duk_hbuffer_resize(thr, comp_ctx->curr_func.h_labelinfos, new_size);
60195 /* XXX: spare handling, slow now */
60196
60197 /* relookup after possible realloc */
60198 p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, comp_ctx->curr_func.h_labelinfos);
60199 li_start = (duk_labelinfo *) (void *) p;
60200 DUK_UNREF(li_start); /* silence scan-build warning */
60201 li = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos));
60202 li--;
60203
60204 /* Labels can be used for iteration statements but also for other statements,
60205 * in particular a label can be used for a block statement. All cases of a
60206 * named label accept a 'break' so that flag is set here. Iteration statements
60207 * also allow 'continue', so that flag is updated when we figure out the
60208 * statement type.
60209 */
60210
60211 li->flags = DUK_LABEL_FLAG_ALLOW_BREAK;
60212 li->label_id = label_id;
60213 li->h_label = h_label;
60214 li->catch_depth = comp_ctx->curr_func.catch_depth; /* catch depth from current func */
60215 li->pc_label = pc_label;
60216
60217 DUK_DDD(DUK_DDDPRINT("registered label: flags=0x%08lx, id=%ld, name=%!O, catch_depth=%ld, pc_label=%ld",
60218 (unsigned long) li->flags, (long) li->label_id, (duk_heaphdr *) li->h_label,
60219 (long) li->catch_depth, (long) li->pc_label));
60220}
60221
60222/* Update all labels with matching label_id. */
60223DUK_LOCAL void duk__update_label_flags(duk_compiler_ctx *comp_ctx, duk_int_t label_id, duk_small_uint_t flags) {
60224 duk_uint8_t *p;
60225 duk_labelinfo *li_start, *li;
60226
60227 p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(comp_ctx->thr->heap, comp_ctx->curr_func.h_labelinfos);
60228 li_start = (duk_labelinfo *) (void *) p;
60229 li = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos));
60230
60231 /* Match labels starting from latest; once label_id no longer matches, we can
60232 * safely exit without checking the rest of the labels (only the topmost labels
60233 * are ever updated).
60234 */
60235 while (li > li_start) {
60236 li--;
60237
60238 if (li->label_id != label_id) {
60239 break;
60240 }
60241
60242 DUK_DDD(DUK_DDDPRINT("updating (overwriting) label flags for li=%p, label_id=%ld, flags=%ld",
60243 (void *) li, (long) label_id, (long) flags));
60244
60245 li->flags = flags;
60246 }
60247}
60248
60249/* Lookup active label information. Break/continue distinction is necessary to handle switch
60250 * statement related labels correctly: a switch will only catch a 'break', not a 'continue'.
60251 *
60252 * An explicit label cannot appear multiple times in the active set, but empty labels (unlabelled
60253 * iteration and switch statements) can. A break will match the closest unlabelled or labelled
60254 * statement. A continue will match the closest unlabelled or labelled iteration statement. It is
60255 * a syntax error if a continue matches a labelled switch statement; because an explicit label cannot
60256 * be duplicated, the continue cannot match any valid label outside the switch.
60257 *
60258 * A side effect of these rules is that a LABEL statement related to a switch should never actually
60259 * catch a continue abrupt completion at run-time. Hence an INVALID opcode can be placed in the
60260 * continue slot of the switch's LABEL statement.
60261 */
60262
60263/* XXX: awkward, especially the bunch of separate output values -> output struct? */
60264DUK_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) {
60265 duk_hthread *thr = comp_ctx->thr;
60266 duk_context *ctx = (duk_context *) thr;
60267 duk_uint8_t *p;
60268 duk_labelinfo *li_start, *li_end, *li;
60269 duk_bool_t match = 0;
60270
60271 DUK_DDD(DUK_DDDPRINT("looking up active label: label='%!O', is_break=%ld",
60272 (duk_heaphdr *) h_label, (long) is_break));
60273
60274 DUK_UNREF(ctx);
60275
60276 p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, comp_ctx->curr_func.h_labelinfos);
60277 li_start = (duk_labelinfo *) (void *) p;
60278 li_end = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos));
60279 li = li_end;
60280
60281 /* Match labels starting from latest label because there can be duplicate empty
60282 * labels in the label set.
60283 */
60284 while (li > li_start) {
60285 li--;
60286
60287 if (li->h_label != h_label) {
60288 DUK_DDD(DUK_DDDPRINT("labelinfo[%ld] ->'%!O' != %!O",
60289 (long) (li - li_start),
60290 (duk_heaphdr *) li->h_label,
60291 (duk_heaphdr *) h_label));
60292 continue;
60293 }
60294
60295 DUK_DDD(DUK_DDDPRINT("labelinfo[%ld] -> '%!O' label name matches (still need to check type)",
60296 (long) (li - li_start), (duk_heaphdr *) h_label));
60297
60298 /* currently all labels accept a break, so no explicit check for it now */
60299 DUK_ASSERT(li->flags & DUK_LABEL_FLAG_ALLOW_BREAK);
60300
60301 if (is_break) {
60302 /* break matches always */
60303 match = 1;
60304 break;
60305 } else if (li->flags & DUK_LABEL_FLAG_ALLOW_CONTINUE) {
60306 /* iteration statements allow continue */
60307 match = 1;
60308 break;
60309 } else {
60310 /* continue matched this label -- we can only continue if this is the empty
60311 * label, for which duplication is allowed, and thus there is hope of
60312 * finding a match deeper in the label stack.
60313 */
60314 if (h_label != DUK_HTHREAD_STRING_EMPTY_STRING(thr)) {
11fdf7f2 60315 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LABEL);
7c673cae
FG
60316 } else {
60317 DUK_DDD(DUK_DDDPRINT("continue matched an empty label which does not "
60318 "allow a continue -> continue lookup deeper in label stack"));
60319 }
60320 }
60321 }
60322 /* XXX: match flag is awkward, rework */
60323 if (!match) {
11fdf7f2 60324 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LABEL);
7c673cae
FG
60325 }
60326
60327 DUK_DDD(DUK_DDDPRINT("label match: %!O -> label_id %ld, catch_depth=%ld, pc_label=%ld",
60328 (duk_heaphdr *) h_label, (long) li->label_id,
60329 (long) li->catch_depth, (long) li->pc_label));
60330
60331 *out_label_id = li->label_id;
60332 *out_label_catch_depth = li->catch_depth;
60333 *out_label_pc = li->pc_label;
60334 *out_is_closest = (li == li_end - 1);
60335}
60336
60337DUK_LOCAL void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, duk_int_t len) {
60338 duk_hthread *thr = comp_ctx->thr;
60339 duk_context *ctx = (duk_context *) thr;
60340 duk_size_t new_size;
60341
60342 /* XXX: duk_set_length */
60343 new_size = sizeof(duk_labelinfo) * (duk_size_t) len;
60344 duk_push_int(ctx, len);
60345 duk_put_prop_stridx(ctx, comp_ctx->curr_func.labelnames_idx, DUK_STRIDX_LENGTH);
60346 duk_hbuffer_resize(thr, comp_ctx->curr_func.h_labelinfos, new_size);
60347}
60348
60349/*
60350 * Expression parsing: duk__expr_nud(), duk__expr_led(), duk__expr_lbp(), and helpers.
60351 *
60352 * - duk__expr_nud(): ("null denotation"): process prev_token as a "start" of an expression (e.g. literal)
60353 * - duk__expr_led(): ("left denotation"): process prev_token in the "middle" of an expression (e.g. operator)
60354 * - duk__expr_lbp(): ("left-binding power"): return left-binding power of curr_token
60355 */
60356
60357/* object literal key tracking flags */
60358#define DUK__OBJ_LIT_KEY_PLAIN (1 << 0) /* key encountered as a plain property */
60359#define DUK__OBJ_LIT_KEY_GET (1 << 1) /* key encountered as a getter */
60360#define DUK__OBJ_LIT_KEY_SET (1 << 2) /* key encountered as a setter */
60361
60362DUK_LOCAL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
60363 duk_hthread *thr = comp_ctx->thr;
60364 duk_reg_t reg_obj; /* result reg */
60365 duk_reg_t reg_temp; /* temp reg */
60366 duk_reg_t temp_start; /* temp reg value for start of loop */
60367 duk_small_uint_t max_init_values; /* max # of values initialized in one MPUTARR set */
60368 duk_small_uint_t num_values; /* number of values in current MPUTARR set */
60369 duk_uarridx_t curr_idx; /* current (next) array index */
60370 duk_uarridx_t start_idx; /* start array index of current MPUTARR set */
60371 duk_uarridx_t init_idx; /* last array index explicitly initialized, +1 */
60372 duk_bool_t require_comma; /* next loop requires a comma */
60373
60374 /* DUK_TOK_LBRACKET already eaten, current token is right after that */
60375 DUK_ASSERT(comp_ctx->prev_token.t == DUK_TOK_LBRACKET);
60376
60377 max_init_values = DUK__MAX_ARRAY_INIT_VALUES; /* XXX: depend on available temps? */
60378
60379 reg_obj = DUK__ALLOCTEMP(comp_ctx);
60380 duk__emit_extraop_b_c(comp_ctx,
60381 DUK_EXTRAOP_NEWARR | DUK__EMIT_FLAG_B_IS_TARGET,
60382 reg_obj,
60383 0); /* XXX: patch initial size afterwards? */
60384 temp_start = DUK__GETTEMP(comp_ctx);
60385
60386 /*
60387 * Emit initializers in sets of maximum max_init_values.
60388 * Corner cases such as single value initializers do not have
60389 * special handling now.
60390 *
60391 * Elided elements must not be emitted as 'undefined' values,
60392 * because such values would be enumerable (which is incorrect).
60393 * Also note that trailing elisions must be reflected in the
60394 * length of the final array but cause no elements to be actually
60395 * inserted.
60396 */
60397
60398 curr_idx = 0;
60399 init_idx = 0; /* tracks maximum initialized index + 1 */
60400 start_idx = 0;
60401 require_comma = 0;
60402
60403 for (;;) {
60404 num_values = 0;
60405 DUK__SETTEMP(comp_ctx, temp_start);
60406
60407 if (comp_ctx->curr_token.t == DUK_TOK_RBRACKET) {
60408 break;
60409 }
60410
60411 for (;;) {
60412 if (comp_ctx->curr_token.t == DUK_TOK_RBRACKET) {
60413 /* the outer loop will recheck and exit */
60414 break;
60415 }
60416
60417 /* comma check */
60418 if (require_comma) {
60419 if (comp_ctx->curr_token.t == DUK_TOK_COMMA) {
60420 /* comma after a value, expected */
60421 duk__advance(comp_ctx);
60422 require_comma = 0;
60423 continue;
60424 } else {
60425 goto syntax_error;
60426 }
60427 } else {
60428 if (comp_ctx->curr_token.t == DUK_TOK_COMMA) {
60429 /* elision - flush */
60430 curr_idx++;
60431 duk__advance(comp_ctx);
60432 /* if num_values > 0, MPUTARR emitted by outer loop after break */
60433 break;
60434 }
60435 }
60436 /* else an array initializer element */
60437
60438 /* initial index */
60439 if (num_values == 0) {
60440 start_idx = curr_idx;
60441 reg_temp = DUK__ALLOCTEMP(comp_ctx);
60442 duk__emit_load_int32(comp_ctx, reg_temp, (duk_int32_t) start_idx);
60443 }
60444
60445 reg_temp = DUK__ALLOCTEMP(comp_ctx); /* alloc temp just in case, to update max temp */
60446 DUK__SETTEMP(comp_ctx, reg_temp);
60447 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/);
60448 DUK__SETTEMP(comp_ctx, reg_temp + 1);
60449
60450 num_values++;
60451 curr_idx++;
60452 require_comma = 1;
60453
60454 if (num_values >= max_init_values) {
60455 /* MPUTARR emitted by outer loop */
60456 break;
60457 }
60458 }
60459
60460 if (num_values > 0) {
60461 /* - A is a source register (it's not a write target, but used
60462 * to identify the target object) but can be shuffled.
60463 * - B cannot be shuffled normally because it identifies a range
60464 * of registers, the emitter has special handling for this
60465 * (the "no shuffle" flag must not be set).
60466 * - C is a non-register number and cannot be shuffled, but
60467 * never needs to be.
60468 */
60469 duk__emit_a_b_c(comp_ctx,
60470 DUK_OP_MPUTARR |
60471 DUK__EMIT_FLAG_NO_SHUFFLE_C |
60472 DUK__EMIT_FLAG_A_IS_SOURCE,
60473 (duk_regconst_t) reg_obj,
60474 (duk_regconst_t) temp_start,
60475 (duk_regconst_t) num_values);
60476 init_idx = start_idx + num_values;
60477
60478 /* num_values and temp_start reset at top of outer loop */
60479 }
60480 }
60481
60482 DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RBRACKET);
60483 duk__advance(comp_ctx);
60484
60485 DUK_DDD(DUK_DDDPRINT("array literal done, curridx=%ld, initidx=%ld",
60486 (long) curr_idx, (long) init_idx));
60487
60488 /* trailing elisions? */
60489 if (curr_idx > init_idx) {
60490 /* yes, must set array length explicitly */
60491 DUK_DDD(DUK_DDDPRINT("array literal has trailing elisions which affect its length"));
60492 reg_temp = DUK__ALLOCTEMP(comp_ctx);
60493 duk__emit_load_int32(comp_ctx, reg_temp, (duk_int_t) curr_idx);
60494 duk__emit_extraop_b_c(comp_ctx,
60495 DUK_EXTRAOP_SETALEN,
60496 (duk_regconst_t) reg_obj,
60497 (duk_regconst_t) reg_temp);
60498 }
60499
60500 DUK__SETTEMP(comp_ctx, temp_start);
60501
60502 res->t = DUK_IVAL_PLAIN;
60503 res->x1.t = DUK_ISPEC_REGCONST;
60504 res->x1.regconst = (duk_regconst_t) reg_obj;
60505 return;
60506
60507 syntax_error:
11fdf7f2 60508 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_ARRAY_LITERAL);
7c673cae
FG
60509}
60510
60511/* duplicate/invalid key checks; returns 1 if syntax error */
60512DUK_LOCAL duk_bool_t duk__nud_object_literal_key_check(duk_compiler_ctx *comp_ctx, duk_small_uint_t new_key_flags) {
60513 duk_hthread *thr = comp_ctx->thr;
60514 duk_context *ctx = (duk_context *) thr;
60515 duk_small_uint_t key_flags;
60516
60517 /* [ ... key_obj key ] */
60518
60519 DUK_ASSERT(duk_is_string(ctx, -1));
60520
60521 /*
60522 * 'key_obj' tracks keys encountered so far by associating an
60523 * integer with flags with already encountered keys. The checks
60524 * below implement E5 Section 11.1.5, step 4 for production:
60525 *
60526 * PropertyNameAndValueList: PropertyNameAndValueList , PropertyAssignment
60527 */
60528
60529 duk_dup(ctx, -1); /* [ ... key_obj key key ] */
60530 duk_get_prop(ctx, -3); /* [ ... key_obj key val ] */
60531 key_flags = duk_to_int(ctx, -1);
60532 duk_pop(ctx); /* [ ... key_obj key ] */
60533
60534 if (new_key_flags & DUK__OBJ_LIT_KEY_PLAIN) {
60535 if ((key_flags & DUK__OBJ_LIT_KEY_PLAIN) && comp_ctx->curr_func.is_strict) {
60536 /* step 4.a */
60537 DUK_DDD(DUK_DDDPRINT("duplicate key: plain key appears twice in strict mode"));
60538 return 1;
60539 }
60540 if (key_flags & (DUK__OBJ_LIT_KEY_GET | DUK__OBJ_LIT_KEY_SET)) {
60541 /* step 4.c */
60542 DUK_DDD(DUK_DDDPRINT("duplicate key: plain key encountered after setter/getter"));
60543 return 1;
60544 }
60545 } else {
60546 if (key_flags & DUK__OBJ_LIT_KEY_PLAIN) {
60547 /* step 4.b */
60548 DUK_DDD(DUK_DDDPRINT("duplicate key: getter/setter encountered after plain key"));
60549 return 1;
60550 }
60551 if (key_flags & new_key_flags) {
60552 /* step 4.d */
60553 DUK_DDD(DUK_DDDPRINT("duplicate key: getter/setter encountered twice"));
60554 return 1;
60555 }
60556 }
60557
60558 new_key_flags |= key_flags;
60559 DUK_DDD(DUK_DDDPRINT("setting/updating key %!T flags: 0x%08lx -> 0x%08lx",
60560 (duk_tval *) duk_get_tval(ctx, -1),
60561 (unsigned long) key_flags,
60562 (unsigned long) new_key_flags));
60563 duk_dup(ctx, -1);
60564 duk_push_int(ctx, new_key_flags); /* [ ... key_obj key key flags ] */
60565 duk_put_prop(ctx, -4); /* [ ... key_obj key ] */
60566
60567 return 0;
60568}
60569
60570DUK_LOCAL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
60571 duk_hthread *thr = comp_ctx->thr;
60572 duk_context *ctx = (duk_context *) thr;
60573 duk_reg_t reg_obj; /* result reg */
60574 duk_reg_t reg_key; /* temp reg for key literal */
60575 duk_reg_t reg_temp; /* temp reg */
60576 duk_reg_t temp_start; /* temp reg value for start of loop */
60577 duk_small_uint_t max_init_pairs; /* max # of key-value pairs initialized in one MPUTOBJ set */
60578 duk_small_uint_t num_pairs; /* number of pairs in current MPUTOBJ set */
60579 duk_bool_t first; /* first value: comma must not precede the value */
60580 duk_bool_t is_set, is_get; /* temps */
60581
60582 DUK_ASSERT(comp_ctx->prev_token.t == DUK_TOK_LCURLY);
60583
60584 max_init_pairs = DUK__MAX_OBJECT_INIT_PAIRS; /* XXX: depend on available temps? */
60585
60586 reg_obj = DUK__ALLOCTEMP(comp_ctx);
60587 duk__emit_extraop_b_c(comp_ctx,
60588 DUK_EXTRAOP_NEWOBJ | DUK__EMIT_FLAG_B_IS_TARGET,
60589 reg_obj,
60590 0); /* XXX: patch initial size afterwards? */
60591 temp_start = DUK__GETTEMP(comp_ctx);
60592
60593 /* temp object for tracking / detecting duplicate keys */
60594 duk_push_object(ctx);
60595
60596 /*
60597 * Emit initializers in sets of maximum max_init_pairs keys.
60598 * Setter/getter is handled separately and terminates the
60599 * current set of initializer values. Corner cases such as
60600 * single value initializers do not have special handling now.
60601 */
60602
60603 first = 1;
60604 for (;;) {
60605 num_pairs = 0;
60606 DUK__SETTEMP(comp_ctx, temp_start);
60607
60608 if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
60609 break;
60610 }
60611
60612 for (;;) {
60613 /*
60614 * Three possible element formats:
60615 * 1) PropertyName : AssignmentExpression
60616 * 2) get PropertyName () { FunctionBody }
60617 * 3) set PropertyName ( PropertySetParameterList ) { FunctionBody }
60618 *
60619 * PropertyName can be IdentifierName (includes reserved words), a string
60620 * literal, or a number literal. Note that IdentifierName allows 'get' and
60621 * 'set' too, so we need to look ahead to the next token to distinguish:
60622 *
60623 * { get : 1 }
60624 *
60625 * and
60626 *
60627 * { get foo() { return 1 } }
60628 * { get get() { return 1 } } // 'get' as getter propertyname
60629 *
60630 * Finally, a trailing comma is allowed.
60631 *
60632 * Key name is coerced to string at compile time (and ends up as a
60633 * a string constant) even for numeric keys (e.g. "{1:'foo'}").
60634 * These could be emitted using e.g. LDINT, but that seems hardly
60635 * worth the effort and would increase code size.
60636 */
60637
60638 DUK_DDD(DUK_DDDPRINT("object literal inner loop, curr_token->t = %ld",
60639 (long) comp_ctx->curr_token.t));
60640
60641 if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
60642 /* the outer loop will recheck and exit */
60643 break;
60644 }
60645 if (num_pairs >= max_init_pairs) {
60646 /* MPUTOBJ emitted by outer loop */
60647 break;
60648 }
60649
60650 if (first) {
60651 first = 0;
60652 } else {
60653 if (comp_ctx->curr_token.t != DUK_TOK_COMMA) {
60654 goto syntax_error;
60655 }
60656 duk__advance(comp_ctx);
60657 if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
60658 /* trailing comma followed by rcurly */
60659 break;
60660 }
60661 }
60662
60663 /* advance to get one step of lookup */
60664 duk__advance(comp_ctx);
60665
60666 /* NOTE: "get" and "set" are not officially ReservedWords and the lexer
60667 * currently treats them always like ordinary identifiers (DUK_TOK_GET
60668 * and DUK_TOK_SET are unused). They need to be detected based on the
60669 * identifier string content.
60670 */
60671
60672 is_get = (comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
60673 comp_ctx->prev_token.str1 == DUK_HTHREAD_STRING_GET(thr));
60674 is_set = (comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
60675 comp_ctx->prev_token.str1 == DUK_HTHREAD_STRING_SET(thr));
60676 if ((is_get || is_set) && comp_ctx->curr_token.t != DUK_TOK_COLON) {
60677 /* getter/setter */
60678 duk_int_t fnum;
60679
60680 if (comp_ctx->curr_token.t_nores == DUK_TOK_IDENTIFIER ||
60681 comp_ctx->curr_token.t_nores == DUK_TOK_STRING) {
60682 /* same handling for identifiers and strings */
60683 DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
60684 duk_push_hstring(ctx, comp_ctx->curr_token.str1);
60685 } else if (comp_ctx->curr_token.t == DUK_TOK_NUMBER) {
60686 duk_push_number(ctx, comp_ctx->curr_token.num);
60687 duk_to_string(ctx, -1);
60688 } else {
60689 goto syntax_error;
60690 }
60691
60692 DUK_ASSERT(duk_is_string(ctx, -1));
60693 if (duk__nud_object_literal_key_check(comp_ctx,
60694 (is_get ? DUK__OBJ_LIT_KEY_GET : DUK__OBJ_LIT_KEY_SET))) {
60695 goto syntax_error;
60696 }
60697 reg_key = duk__getconst(comp_ctx);
60698
60699 if (num_pairs > 0) {
60700 /* - A is a source register (it's not a write target, but used
60701 * to identify the target object) but can be shuffled.
60702 * - B cannot be shuffled normally because it identifies a range
60703 * of registers, the emitter has special handling for this
60704 * (the "no shuffle" flag must not be set).
60705 * - C is a non-register number and cannot be shuffled, but
60706 * never needs to be.
60707 */
60708 duk__emit_a_b_c(comp_ctx,
60709 DUK_OP_MPUTOBJ |
60710 DUK__EMIT_FLAG_NO_SHUFFLE_C |
60711 DUK__EMIT_FLAG_A_IS_SOURCE,
60712 reg_obj,
60713 temp_start,
60714 num_pairs);
60715 num_pairs = 0;
60716 DUK__SETTEMP(comp_ctx, temp_start);
60717 }
60718
60719 /* curr_token = get/set name */
60720 fnum = duk__parse_func_like_fnum(comp_ctx, 0 /*is_decl*/, 1 /*is_setget*/);
60721
60722 DUK_ASSERT(DUK__GETTEMP(comp_ctx) == temp_start);
60723 reg_temp = DUK__ALLOCTEMP(comp_ctx);
60724 duk__emit_a_bc(comp_ctx,
60725 DUK_OP_LDCONST,
60726 (duk_regconst_t) reg_temp,
60727 (duk_regconst_t) reg_key);
60728 reg_temp = DUK__ALLOCTEMP(comp_ctx);
60729 duk__emit_a_bc(comp_ctx,
60730 DUK_OP_CLOSURE,
60731 (duk_regconst_t) reg_temp,
60732 (duk_regconst_t) fnum);
60733
60734 /* Slot C is used in a non-standard fashion (range of regs),
60735 * emitter code has special handling for it (must not set the
60736 * "no shuffle" flag).
60737 */
60738 duk__emit_extraop_b_c(comp_ctx,
60739 (is_get ? DUK_EXTRAOP_INITGET : DUK_EXTRAOP_INITSET),
60740 reg_obj,
60741 temp_start); /* temp_start+0 = key, temp_start+1 = closure */
60742
60743 DUK__SETTEMP(comp_ctx, temp_start);
60744 } else {
60745 /* normal key/value */
60746 if (comp_ctx->prev_token.t_nores == DUK_TOK_IDENTIFIER ||
60747 comp_ctx->prev_token.t_nores == DUK_TOK_STRING) {
60748 /* same handling for identifiers and strings */
60749 DUK_ASSERT(comp_ctx->prev_token.str1 != NULL);
60750 duk_push_hstring(ctx, comp_ctx->prev_token.str1);
60751 } else if (comp_ctx->prev_token.t == DUK_TOK_NUMBER) {
60752 duk_push_number(ctx, comp_ctx->prev_token.num);
60753 duk_to_string(ctx, -1);
60754 } else {
60755 goto syntax_error;
60756 }
60757
60758 DUK_ASSERT(duk_is_string(ctx, -1));
60759 if (duk__nud_object_literal_key_check(comp_ctx, DUK__OBJ_LIT_KEY_PLAIN)) {
60760 goto syntax_error;
60761 }
60762 reg_key = duk__getconst(comp_ctx);
60763
60764 reg_temp = DUK__ALLOCTEMP(comp_ctx);
60765 duk__emit_a_bc(comp_ctx,
60766 DUK_OP_LDCONST,
60767 (duk_regconst_t) reg_temp,
60768 (duk_regconst_t) reg_key);
60769 duk__advance_expect(comp_ctx, DUK_TOK_COLON);
60770
60771 reg_temp = DUK__ALLOCTEMP(comp_ctx); /* alloc temp just in case, to update max temp */
60772 DUK__SETTEMP(comp_ctx, reg_temp);
60773 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/);
60774 DUK__SETTEMP(comp_ctx, reg_temp + 1);
60775
60776 num_pairs++;
60777 }
60778 }
60779
60780 if (num_pairs > 0) {
60781 /* See MPUTOBJ comments above. */
60782 duk__emit_a_b_c(comp_ctx,
60783 DUK_OP_MPUTOBJ |
60784 DUK__EMIT_FLAG_NO_SHUFFLE_C |
60785 DUK__EMIT_FLAG_A_IS_SOURCE,
60786 reg_obj,
60787 temp_start,
60788 num_pairs);
60789
60790 /* num_pairs and temp_start reset at top of outer loop */
60791 }
60792 }
60793
60794 DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RCURLY);
60795 duk__advance(comp_ctx);
60796
60797 DUK__SETTEMP(comp_ctx, temp_start);
60798
60799 res->t = DUK_IVAL_PLAIN;
60800 res->x1.t = DUK_ISPEC_REGCONST;
60801 res->x1.regconst = (duk_regconst_t) reg_obj;
60802
60803 DUK_DDD(DUK_DDDPRINT("final tracking object: %!T",
60804 (duk_tval *) duk_get_tval(ctx, -1)));
60805 duk_pop(ctx);
60806 return;
60807
60808 syntax_error:
11fdf7f2 60809 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_OBJECT_LITERAL);
7c673cae
FG
60810}
60811
60812/* Parse argument list. Arguments are written to temps starting from
60813 * "next temp". Returns number of arguments parsed. Expects left paren
60814 * to be already eaten, and eats the right paren before returning.
60815 */
60816DUK_LOCAL duk_int_t duk__parse_arguments(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
60817 duk_int_t nargs = 0;
60818 duk_reg_t reg_temp;
60819
60820 /* Note: expect that caller has already eaten the left paren */
60821
60822 DUK_DDD(DUK_DDDPRINT("start parsing arguments, prev_token.t=%ld, curr_token.t=%ld",
60823 (long) comp_ctx->prev_token.t, (long) comp_ctx->curr_token.t));
60824
60825 for (;;) {
60826 if (comp_ctx->curr_token.t == DUK_TOK_RPAREN) {
60827 break;
60828 }
60829 if (nargs > 0) {
60830 duk__advance_expect(comp_ctx, DUK_TOK_COMMA);
60831 }
60832
60833 /* We want the argument expression value to go to "next temp"
60834 * without additional moves. That should almost always be the
60835 * case, but we double check after expression parsing.
60836 *
60837 * This is not the cleanest possible approach.
60838 */
60839
60840 reg_temp = DUK__ALLOCTEMP(comp_ctx); /* bump up "allocated" reg count, just in case */
60841 DUK__SETTEMP(comp_ctx, reg_temp);
60842
60843 /* binding power must be high enough to NOT allow comma expressions directly */
60844 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp); /* always allow 'in', coerce to 'tr' just in case */
60845
60846 DUK__SETTEMP(comp_ctx, reg_temp + 1);
60847 nargs++;
60848
60849 DUK_DDD(DUK_DDDPRINT("argument #%ld written into reg %ld", (long) nargs, (long) reg_temp));
60850 }
60851
60852 /* eat the right paren */
60853 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
60854
60855 DUK_DDD(DUK_DDDPRINT("end parsing arguments"));
60856
60857 return nargs;
60858}
60859
60860DUK_LOCAL duk_bool_t duk__expr_is_empty(duk_compiler_ctx *comp_ctx) {
60861 /* empty expressions can be detected conveniently with nud/led counts */
60862 return (comp_ctx->curr_func.nud_count == 0) &&
60863 (comp_ctx->curr_func.led_count == 0);
60864}
60865
60866DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
60867 duk_hthread *thr = comp_ctx->thr;
60868 duk_context *ctx = (duk_context *) thr;
60869 duk_token *tk;
60870 duk_reg_t temp_at_entry;
60871 duk_small_int_t tok;
60872 duk_uint32_t args; /* temp variable to pass constants and flags to shared code */
60873
60874 /*
60875 * ctx->prev_token token to process with duk__expr_nud()
60876 * ctx->curr_token updated by caller
60877 *
60878 * Note: the token in the switch below has already been eaten.
60879 */
60880
60881 temp_at_entry = DUK__GETTEMP(comp_ctx);
60882
60883 comp_ctx->curr_func.nud_count++;
60884
60885 tk = &comp_ctx->prev_token;
60886 tok = tk->t;
60887 res->t = DUK_IVAL_NONE;
60888
60889 DUK_DDD(DUK_DDDPRINT("duk__expr_nud(), prev_token.t=%ld, allow_in=%ld, paren_level=%ld",
60890 (long) tk->t, (long) comp_ctx->curr_func.allow_in, (long) comp_ctx->curr_func.paren_level));
60891
60892 switch (tok) {
60893
60894 /* PRIMARY EXPRESSIONS */
60895
60896 case DUK_TOK_THIS: {
60897 duk_reg_t reg_temp;
60898 reg_temp = DUK__ALLOCTEMP(comp_ctx);
60899 duk__emit_extraop_bc(comp_ctx,
60900 DUK_EXTRAOP_LDTHIS,
60901 (duk_regconst_t) reg_temp);
60902 res->t = DUK_IVAL_PLAIN;
60903 res->x1.t = DUK_ISPEC_REGCONST;
60904 res->x1.regconst = (duk_regconst_t) reg_temp;
60905 return;
60906 }
60907 case DUK_TOK_IDENTIFIER: {
60908 res->t = DUK_IVAL_VAR;
60909 res->x1.t = DUK_ISPEC_VALUE;
60910 duk_push_hstring(ctx, tk->str1);
60911 duk_replace(ctx, res->x1.valstack_idx);
60912 return;
60913 }
60914 case DUK_TOK_NULL: {
60915 duk_push_null(ctx);
60916 goto plain_value;
60917 }
60918 case DUK_TOK_TRUE: {
60919 duk_push_true(ctx);
60920 goto plain_value;
60921 }
60922 case DUK_TOK_FALSE: {
60923 duk_push_false(ctx);
60924 goto plain_value;
60925 }
60926 case DUK_TOK_NUMBER: {
60927 duk_push_number(ctx, tk->num);
60928 goto plain_value;
60929 }
60930 case DUK_TOK_STRING: {
60931 DUK_ASSERT(tk->str1 != NULL);
60932 duk_push_hstring(ctx, tk->str1);
60933 goto plain_value;
60934 }
60935 case DUK_TOK_REGEXP: {
60936#ifdef DUK_USE_REGEXP_SUPPORT
60937 duk_reg_t reg_temp;
60938 duk_regconst_t rc_re_bytecode; /* const */
60939 duk_regconst_t rc_re_source; /* const */
60940
60941 DUK_ASSERT(tk->str1 != NULL);
60942 DUK_ASSERT(tk->str2 != NULL);
60943
60944 DUK_DDD(DUK_DDDPRINT("emitting regexp op, str1=%!O, str2=%!O",
60945 (duk_heaphdr *) tk->str1,
60946 (duk_heaphdr *) tk->str2));
60947
60948 reg_temp = DUK__ALLOCTEMP(comp_ctx);
60949 duk_push_hstring(ctx, tk->str1);
60950 duk_push_hstring(ctx, tk->str2);
60951
60952 /* [ ... pattern flags ] */
60953
60954 duk_regexp_compile(thr);
60955
60956 /* [ ... escaped_source bytecode ] */
60957
60958 rc_re_bytecode = duk__getconst(comp_ctx);
60959 rc_re_source = duk__getconst(comp_ctx);
60960
60961 duk__emit_a_b_c(comp_ctx,
60962 DUK_OP_REGEXP,
60963 (duk_regconst_t) reg_temp /*a*/,
60964 rc_re_bytecode /*b*/,
60965 rc_re_source /*c*/);
60966
60967 res->t = DUK_IVAL_PLAIN;
60968 res->x1.t = DUK_ISPEC_REGCONST;
60969 res->x1.regconst = (duk_regconst_t) reg_temp;
60970 return;
60971#else /* DUK_USE_REGEXP_SUPPORT */
60972 goto syntax_error;
60973#endif /* DUK_USE_REGEXP_SUPPORT */
60974 }
60975 case DUK_TOK_LBRACKET: {
60976 DUK_DDD(DUK_DDDPRINT("parsing array literal"));
60977 duk__nud_array_literal(comp_ctx, res);
60978 return;
60979 }
60980 case DUK_TOK_LCURLY: {
60981 DUK_DDD(DUK_DDDPRINT("parsing object literal"));
60982 duk__nud_object_literal(comp_ctx, res);
60983 return;
60984 }
60985 case DUK_TOK_LPAREN: {
60986 duk_bool_t prev_allow_in;
60987
60988 comp_ctx->curr_func.paren_level++;
60989 prev_allow_in = comp_ctx->curr_func.allow_in;
60990 comp_ctx->curr_func.allow_in = 1; /* reset 'allow_in' for parenthesized expression */
60991
60992 duk__expr(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); /* Expression, terminates at a ')' */
60993
60994 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
60995 comp_ctx->curr_func.allow_in = prev_allow_in;
60996 comp_ctx->curr_func.paren_level--;
60997 return;
60998 }
60999
61000 /* MEMBER/NEW/CALL EXPRESSIONS */
61001
61002 case DUK_TOK_NEW: {
61003 /*
61004 * Parsing an expression starting with 'new' is tricky because
61005 * there are multiple possible productions deriving from
61006 * LeftHandSideExpression which begin with 'new'.
61007 *
61008 * We currently resort to one-token lookahead to distinguish the
61009 * cases. Hopefully this is correct. The binding power must be
61010 * such that parsing ends at an LPAREN (CallExpression) but not at
61011 * a PERIOD or LBRACKET (MemberExpression).
61012 *
61013 * See doc/compiler.rst for discussion on the parsing approach,
61014 * and testcases/test-dev-new.js for a bunch of documented tests.
61015 */
61016
61017 duk_reg_t reg_target;
61018 duk_int_t nargs;
61019
61020 DUK_DDD(DUK_DDDPRINT("begin parsing new expression"));
61021
61022 reg_target = DUK__ALLOCTEMP(comp_ctx);
61023 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_CALL /*rbp_flags*/, reg_target /*forced_reg*/);
61024 DUK__SETTEMP(comp_ctx, reg_target + 1);
61025
61026 if (comp_ctx->curr_token.t == DUK_TOK_LPAREN) {
61027 /* 'new' MemberExpression Arguments */
61028 DUK_DDD(DUK_DDDPRINT("new expression has argument list"));
61029 duk__advance(comp_ctx);
61030 nargs = duk__parse_arguments(comp_ctx, res); /* parse args starting from "next temp", reg_target + 1 */
61031 /* right paren eaten */
61032 } else {
61033 /* 'new' MemberExpression */
61034 DUK_DDD(DUK_DDDPRINT("new expression has no argument list"));
61035 nargs = 0;
61036 }
61037
61038 /* Opcode slot C is used in a non-standard way, so shuffling
61039 * is not allowed.
61040 */
61041 duk__emit_a_b_c(comp_ctx,
61042 DUK_OP_NEW | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_C,
61043 0 /*unused*/,
61044 reg_target /*target*/,
61045 nargs /*num_args*/);
61046
61047 DUK_DDD(DUK_DDDPRINT("end parsing new expression"));
61048
61049 res->t = DUK_IVAL_PLAIN;
61050 res->x1.t = DUK_ISPEC_REGCONST;
61051 res->x1.regconst = (duk_regconst_t) reg_target;
61052 return;
61053 }
61054
61055 /* FUNCTION EXPRESSIONS */
61056
61057 case DUK_TOK_FUNCTION: {
61058 /* Function expression. Note that any statement beginning with 'function'
61059 * is handled by the statement parser as a function declaration, or a
61060 * non-standard function expression/statement (or a SyntaxError). We only
61061 * handle actual function expressions (occurring inside an expression) here.
61062 *
61063 * O(depth^2) parse count for inner functions is handled by recording a
61064 * lexer offset on the first compilation pass, so that the function can
61065 * be efficiently skipped on the second pass. This is encapsulated into
61066 * duk__parse_func_like_fnum().
61067 */
61068
61069 duk_reg_t reg_temp;
61070 duk_int_t fnum;
61071
61072 reg_temp = DUK__ALLOCTEMP(comp_ctx);
61073
61074 /* curr_token follows 'function' */
61075 fnum = duk__parse_func_like_fnum(comp_ctx, 0 /*is_decl*/, 0 /*is_setget*/);
61076 DUK_DDD(DUK_DDDPRINT("parsed inner function -> fnum %ld", (long) fnum));
61077
61078 duk__emit_a_bc(comp_ctx,
61079 DUK_OP_CLOSURE,
61080 (duk_regconst_t) reg_temp /*a*/,
61081 (duk_regconst_t) fnum /*bc*/);
61082
61083 res->t = DUK_IVAL_PLAIN;
61084 res->x1.t = DUK_ISPEC_REGCONST;
61085 res->x1.regconst = (duk_regconst_t) reg_temp;
61086 return;
61087 }
61088
61089 /* UNARY EXPRESSIONS */
61090
61091 case DUK_TOK_DELETE: {
61092 /* Delete semantics are a bit tricky. The description in E5 specification
61093 * is kind of confusing, because it distinguishes between resolvability of
61094 * a reference (which is only known at runtime) seemingly at compile time
61095 * (= SyntaxError throwing).
61096 */
61097 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
61098 if (res->t == DUK_IVAL_VAR) {
61099 /* not allowed in strict mode, regardless of whether resolves;
61100 * in non-strict mode DELVAR handles both non-resolving and
61101 * resolving cases (the specification description is a bit confusing).
61102 */
61103
61104 duk_reg_t reg_temp;
61105 duk_reg_t reg_varbind;
61106 duk_regconst_t rc_varname;
61107
61108 if (comp_ctx->curr_func.is_strict) {
11fdf7f2 61109 DUK_ERROR_SYNTAX(thr, DUK_STR_CANNOT_DELETE_IDENTIFIER);
7c673cae
FG
61110 }
61111
61112 DUK__SETTEMP(comp_ctx, temp_at_entry);
61113 reg_temp = DUK__ALLOCTEMP(comp_ctx);
61114
61115 duk_dup(ctx, res->x1.valstack_idx);
61116 if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
61117 /* register bound variables are non-configurable -> always false */
61118 duk__emit_extraop_bc(comp_ctx,
61119 DUK_EXTRAOP_LDFALSE,
61120 (duk_regconst_t) reg_temp);
61121 } else {
61122 duk_dup(ctx, res->x1.valstack_idx);
61123 rc_varname = duk__getconst(comp_ctx);
61124 duk__emit_a_b(comp_ctx,
61125 DUK_OP_DELVAR,
61126 (duk_regconst_t) reg_temp,
61127 (duk_regconst_t) rc_varname);
61128 }
61129 res->t = DUK_IVAL_PLAIN;
61130 res->x1.t = DUK_ISPEC_REGCONST;
61131 res->x1.regconst = (duk_regconst_t) reg_temp;
61132 } else if (res->t == DUK_IVAL_PROP) {
61133 duk_reg_t reg_temp;
61134 duk_reg_t reg_obj;
61135 duk_regconst_t rc_key;
61136
61137 DUK__SETTEMP(comp_ctx, temp_at_entry);
61138 reg_temp = DUK__ALLOCTEMP(comp_ctx);
61139 reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
61140 rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
61141 duk__emit_a_b_c(comp_ctx,
61142 DUK_OP_DELPROP,
61143 (duk_regconst_t) reg_temp,
61144 (duk_regconst_t) reg_obj,
61145 rc_key);
61146
61147 res->t = DUK_IVAL_PLAIN;
61148 res->x1.t = DUK_ISPEC_REGCONST;
61149 res->x1.regconst = (duk_regconst_t) reg_temp;
61150 } else {
61151 /* non-Reference deletion is always 'true', even in strict mode */
61152 duk_push_true(ctx);
61153 goto plain_value;
61154 }
61155 return;
61156 }
61157 case DUK_TOK_VOID: {
61158 duk__expr_toplain_ignore(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
61159 duk_push_undefined(ctx);
61160 goto plain_value;
61161 }
61162 case DUK_TOK_TYPEOF: {
61163 /* 'typeof' must handle unresolvable references without throwing
61164 * a ReferenceError (E5 Section 11.4.3). Register mapped values
61165 * will never be unresolvable so special handling is only required
61166 * when an identifier is a "slow path" one.
61167 */
61168 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
61169
61170 if (res->t == DUK_IVAL_VAR) {
61171 duk_reg_t reg_varbind;
61172 duk_regconst_t rc_varname;
61173 duk_reg_t reg_temp;
61174
61175 duk_dup(ctx, res->x1.valstack_idx);
61176 if (!duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
61177 DUK_DDD(DUK_DDDPRINT("typeof for an identifier name which could not be resolved "
61178 "at compile time, need to use special run-time handling"));
61179 reg_temp = DUK__ALLOCTEMP(comp_ctx);
61180 duk__emit_extraop_b_c(comp_ctx,
61181 DUK_EXTRAOP_TYPEOFID | DUK__EMIT_FLAG_B_IS_TARGET,
61182 reg_temp,
61183 rc_varname);
61184 res->t = DUK_IVAL_PLAIN;
61185 res->x1.t = DUK_ISPEC_REGCONST;
61186 res->x1.regconst = (duk_regconst_t) reg_temp;
61187 return;
61188 }
61189 }
61190
61191 args = (DUK_EXTRAOP_TYPEOF << 8) + 0;
61192 goto unary_extraop;
61193 }
61194 case DUK_TOK_INCREMENT: {
61195 args = (DUK_OP_PREINCR << 8) + 0;
61196 goto preincdec;
61197 }
61198 case DUK_TOK_DECREMENT: {
61199 args = (DUK_OP_PREDECR << 8) + 0;
61200 goto preincdec;
61201 }
61202 case DUK_TOK_ADD: {
61203 /* unary plus */
61204 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
61205 if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE &&
61206 duk_is_number(ctx, res->x1.valstack_idx)) {
61207 /* unary plus of a number is identity */
61208 ;
61209 return;
61210 }
61211 args = (DUK_EXTRAOP_UNP << 8) + 0;
61212 goto unary_extraop;
61213 }
61214 case DUK_TOK_SUB: {
61215 /* unary minus */
61216 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
61217 if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE &&
61218 duk_is_number(ctx, res->x1.valstack_idx)) {
11fdf7f2
TL
61219 /* this optimization is important to handle negative literals
61220 * (which are not directly provided by the lexical grammar)
7c673cae 61221 */
11fdf7f2 61222 duk_tval *tv_num;
7c673cae
FG
61223 duk_double_union du;
61224
11fdf7f2 61225 tv_num = DUK_GET_TVAL_POSIDX(ctx, res->x1.valstack_idx);
7c673cae
FG
61226 DUK_ASSERT(tv_num != NULL);
61227 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_num));
61228 du.d = DUK_TVAL_GET_NUMBER(tv_num);
61229 du.d = -du.d;
61230 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
61231 DUK_TVAL_SET_NUMBER(tv_num, du.d);
61232 return;
61233 }
61234 args = (DUK_EXTRAOP_UNM << 8) + 0;
61235 goto unary_extraop;
61236 }
61237 case DUK_TOK_BNOT: {
61238 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
61239 args = (DUK_EXTRAOP_BNOT << 8) + 0;
61240 goto unary_extraop;
61241 }
61242 case DUK_TOK_LNOT: {
61243 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
61244 if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE) {
61245 /* Very minimal inlining to handle common idioms '!0' and '!1',
61246 * and also boolean arguments like '!false' and '!true'.
61247 */
11fdf7f2 61248 duk_tval *tv_val;
7c673cae 61249
11fdf7f2 61250 tv_val = DUK_GET_TVAL_POSIDX(ctx, res->x1.valstack_idx);
7c673cae
FG
61251 DUK_ASSERT(tv_val != NULL);
61252 if (DUK_TVAL_IS_NUMBER(tv_val)) {
61253 duk_double_t d;
61254 d = DUK_TVAL_GET_NUMBER(tv_val);
61255 if (d == 0.0) {
61256 /* Matches both +0 and -0 on purpose. */
61257 DUK_DDD(DUK_DDDPRINT("inlined lnot: !0 -> true"));
61258 DUK_TVAL_SET_BOOLEAN_TRUE(tv_val);
61259 return;
61260 } else if (d == 1.0) {
61261 DUK_DDD(DUK_DDDPRINT("inlined lnot: !1 -> false"));
61262 DUK_TVAL_SET_BOOLEAN_FALSE(tv_val);
61263 return;
61264 }
61265 } else if (DUK_TVAL_IS_BOOLEAN(tv_val)) {
61266 duk_small_int_t v;
61267 v = DUK_TVAL_GET_BOOLEAN(tv_val);
61268 DUK_DDD(DUK_DDDPRINT("inlined lnot boolean: %ld", (long) v));
61269 DUK_ASSERT(v == 0 || v == 1);
61270 DUK_TVAL_SET_BOOLEAN(tv_val, v ^ 0x01);
61271 return;
61272 }
61273 }
61274 args = (DUK_EXTRAOP_LNOT << 8) + 0;
61275 goto unary_extraop;
61276 }
61277
61278 } /* end switch */
61279
11fdf7f2 61280 DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR);
7c673cae
FG
61281 return;
61282
61283 unary_extraop:
61284 {
61285 /* Note: must coerce to a (writable) temp register, so that e.g. "!x" where x
61286 * is a reg-mapped variable works correctly (does not mutate the variable register).
61287 */
61288
61289 duk_reg_t reg_temp;
61290 reg_temp = duk__ivalue_toregconst_raw(comp_ctx, res, -1 /*forced_reg*/, DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
61291 duk__emit_extraop_bc(comp_ctx,
61292 (args >> 8),
61293 (duk_regconst_t) reg_temp);
61294 res->t = DUK_IVAL_PLAIN;
61295 res->x1.t = DUK_ISPEC_REGCONST;
61296 res->x1.regconst = (duk_regconst_t) reg_temp;
61297 return;
61298 }
61299
61300 preincdec:
61301 {
61302 /* preincrement and predecrement */
61303 duk_reg_t reg_res;
61304 duk_small_uint_t args_op = args >> 8;
61305
61306 /* Specific assumptions for opcode numbering. */
61307 DUK_ASSERT(DUK_OP_PREINCR + 4 == DUK_OP_PREINCV);
61308 DUK_ASSERT(DUK_OP_PREDECR + 4 == DUK_OP_PREDECV);
61309 DUK_ASSERT(DUK_OP_PREINCR + 8 == DUK_OP_PREINCP);
61310 DUK_ASSERT(DUK_OP_PREDECR + 8 == DUK_OP_PREDECP);
61311
61312 reg_res = DUK__ALLOCTEMP(comp_ctx);
61313
61314 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
61315 if (res->t == DUK_IVAL_VAR) {
61316 duk_hstring *h_varname;
61317 duk_reg_t reg_varbind;
61318 duk_regconst_t rc_varname;
61319
61320 h_varname = duk_get_hstring(ctx, res->x1.valstack_idx);
61321 DUK_ASSERT(h_varname != NULL);
61322
61323 if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
61324 goto syntax_error;
61325 }
61326
61327 duk_dup(ctx, res->x1.valstack_idx);
61328 if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
61329 duk__emit_a_bc(comp_ctx,
61330 args_op, /* e.g. DUK_OP_PREINCR */
61331 (duk_regconst_t) reg_res,
61332 (duk_regconst_t) reg_varbind);
61333 } else {
61334 duk__emit_a_bc(comp_ctx,
61335 args_op + 4, /* e.g. DUK_OP_PREINCV */
61336 (duk_regconst_t) reg_res,
61337 rc_varname);
61338 }
61339
61340 DUK_DDD(DUK_DDDPRINT("preincdec to '%!O' -> reg_varbind=%ld, rc_varname=%ld",
61341 (duk_heaphdr *) h_varname, (long) reg_varbind, (long) rc_varname));
61342 } else if (res->t == DUK_IVAL_PROP) {
61343 duk_reg_t reg_obj; /* allocate to reg only (not const) */
61344 duk_regconst_t rc_key;
61345 reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
61346 rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
61347 duk__emit_a_b_c(comp_ctx,
61348 args_op + 8, /* e.g. DUK_OP_PREINCP */
61349 (duk_regconst_t) reg_res,
61350 (duk_regconst_t) reg_obj,
61351 rc_key);
61352 } else {
61353 /* Technically return value is not needed because INVLHS will
61354 * unconditially throw a ReferenceError. Coercion is necessary
61355 * for proper semantics (consider ToNumber() called for an object).
61356 * Use DUK_EXTRAOP_UNP with a dummy register to get ToNumber().
61357 */
61358
61359 duk__ivalue_toforcedreg(comp_ctx, res, reg_res);
61360 duk__emit_extraop_bc(comp_ctx,
61361 DUK_EXTRAOP_UNP,
61362 reg_res); /* for side effects, result ignored */
61363 duk__emit_extraop_only(comp_ctx,
61364 DUK_EXTRAOP_INVLHS);
61365 }
61366 res->t = DUK_IVAL_PLAIN;
61367 res->x1.t = DUK_ISPEC_REGCONST;
61368 res->x1.regconst = (duk_regconst_t) reg_res;
61369 DUK__SETTEMP(comp_ctx, reg_res + 1);
61370 return;
61371 }
61372
61373 plain_value:
61374 {
61375 /* Stack top contains plain value */
61376 res->t = DUK_IVAL_PLAIN;
61377 res->x1.t = DUK_ISPEC_VALUE;
61378 duk_replace(ctx, res->x1.valstack_idx);
61379 return;
61380 }
61381
61382 syntax_error:
11fdf7f2 61383 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_EXPRESSION);
7c673cae
FG
61384}
61385
61386/* XXX: add flag to indicate whether caller cares about return value; this
61387 * affects e.g. handling of assignment expressions. This change needs API
61388 * changes elsewhere too.
61389 */
61390DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_ivalue *res) {
61391 duk_hthread *thr = comp_ctx->thr;
61392 duk_context *ctx = (duk_context *) thr;
61393 duk_token *tk;
61394 duk_small_int_t tok;
61395 duk_uint32_t args; /* temp variable to pass constants and flags to shared code */
61396
61397 /*
61398 * ctx->prev_token token to process with duk__expr_led()
61399 * ctx->curr_token updated by caller
61400 */
61401
61402 comp_ctx->curr_func.led_count++;
61403
61404 /* The token in the switch has already been eaten here */
61405 tk = &comp_ctx->prev_token;
61406 tok = tk->t;
61407
61408 DUK_DDD(DUK_DDDPRINT("duk__expr_led(), prev_token.t=%ld, allow_in=%ld, paren_level=%ld",
61409 (long) tk->t, (long) comp_ctx->curr_func.allow_in, (long) comp_ctx->curr_func.paren_level));
61410
61411 /* XXX: default priority for infix operators is duk__expr_lbp(tok) -> get it here? */
61412
61413 switch (tok) {
61414
61415 /* PRIMARY EXPRESSIONS */
61416
61417 case DUK_TOK_PERIOD: {
61418 /* Property access expressions are critical for correct LHS ordering,
61419 * see comments in duk__expr()!
11fdf7f2
TL
61420 *
61421 * A conservative approach would be to use duk__ivalue_totempconst()
61422 * for 'left'. However, allowing a reg-bound variable seems safe here
61423 * and is nice because "foo.bar" is a common expression. If the ivalue
61424 * is used in an expression a GETPROP will occur before any changes to
61425 * the base value can occur. If the ivalue is used as an assignment
61426 * LHS, the assignment code will ensure the base value is safe from
61427 * RHS mutation.
7c673cae
FG
61428 */
61429
11fdf7f2 61430 /* XXX: This now coerces an identifier into a GETVAR to a temp, which
7c673cae
FG
61431 * causes an extra LDREG in call setup. It's sufficient to coerce to a
61432 * unary ivalue?
61433 */
61434 duk__ivalue_toplain(comp_ctx, left);
61435
61436 /* NB: must accept reserved words as property name */
61437 if (comp_ctx->curr_token.t_nores != DUK_TOK_IDENTIFIER) {
11fdf7f2 61438 DUK_ERROR_SYNTAX(thr, DUK_STR_EXPECTED_IDENTIFIER);
7c673cae
FG
61439 }
61440
61441 res->t = DUK_IVAL_PROP;
61442 duk__copy_ispec(comp_ctx, &left->x1, &res->x1); /* left.x1 -> res.x1 */
61443 DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
61444 duk_push_hstring(ctx, comp_ctx->curr_token.str1);
61445 duk_replace(ctx, res->x2.valstack_idx);
61446 res->x2.t = DUK_ISPEC_VALUE;
61447
61448 /* special RegExp literal handling after IdentifierName */
61449 comp_ctx->curr_func.reject_regexp_in_adv = 1;
61450
61451 duk__advance(comp_ctx);
61452 return;
61453 }
61454 case DUK_TOK_LBRACKET: {
61455 /* Property access expressions are critical for correct LHS ordering,
61456 * see comments in duk__expr()!
61457 */
61458
61459 /* XXX: optimize temp reg use */
61460 /* XXX: similar coercion issue as in DUK_TOK_PERIOD */
7c673cae
FG
61461 /* XXX: coerce to regs? it might be better for enumeration use, where the
61462 * same PROP ivalue is used multiple times. Or perhaps coerce PROP further
61463 * there?
61464 */
11fdf7f2
TL
61465 /* XXX: for simple cases like x['y'] an unnecessary LDREG is
61466 * emitted for the base value; could avoid it if we knew that
61467 * the key expression is safe (e.g. just a single literal).
61468 */
7c673cae 61469
11fdf7f2
TL
61470 /* The 'left' value must not be a register bound variable
61471 * because it may be mutated during the rest of the expression
61472 * and E5.1 Section 11.2.1 specifies the order of evaluation
61473 * so that the base value is evaluated first.
61474 * See: test-bug-nested-prop-mutate.js.
61475 */
61476 duk__ivalue_totempconst(comp_ctx, left);
7c673cae
FG
61477 duk__expr_toplain(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); /* Expression, ']' terminates */
61478 duk__advance_expect(comp_ctx, DUK_TOK_RBRACKET);
61479
61480 res->t = DUK_IVAL_PROP;
61481 duk__copy_ispec(comp_ctx, &res->x1, &res->x2); /* res.x1 -> res.x2 */
61482 duk__copy_ispec(comp_ctx, &left->x1, &res->x1); /* left.x1 -> res.x1 */
61483 return;
61484 }
61485 case DUK_TOK_LPAREN: {
61486 /* function call */
61487 duk_reg_t reg_cs = DUK__ALLOCTEMPS(comp_ctx, 2);
61488 duk_int_t nargs;
61489 duk_small_uint_t call_flags = 0;
61490
61491 /*
61492 * XXX: attempt to get the call result to "next temp" whenever
61493 * possible to avoid unnecessary register shuffles.
61494 *
61495 * XXX: CSPROP (and CSREG) can overwrite the call target register, and save one temp,
61496 * if the call target is a temporary register and at the top of the temp reg "stack".
61497 */
61498
61499 /*
61500 * Setup call: target and 'this' binding. Three cases:
61501 *
61502 * 1. Identifier base (e.g. "foo()")
61503 * 2. Property base (e.g. "foo.bar()")
61504 * 3. Register base (e.g. "foo()()"; i.e. when a return value is a function)
61505 */
61506
61507 if (left->t == DUK_IVAL_VAR) {
61508 duk_hstring *h_varname;
61509 duk_reg_t reg_varbind;
61510 duk_regconst_t rc_varname;
61511
61512 DUK_DDD(DUK_DDDPRINT("function call with identifier base"));
61513
61514 h_varname = duk_get_hstring(ctx, left->x1.valstack_idx);
61515 DUK_ASSERT(h_varname != NULL);
61516 if (h_varname == DUK_HTHREAD_STRING_EVAL(thr)) {
61517 /* Potential direct eval call detected, flag the CALL
61518 * so that a run-time "direct eval" check is made and
61519 * special behavior may be triggered. Note that this
61520 * does not prevent 'eval' from being register bound.
61521 */
61522 DUK_DDD(DUK_DDDPRINT("function call with identifier 'eval' "
61523 "-> enabling EVALCALL flag, marking function "
61524 "as may_direct_eval"));
61525 call_flags |= DUK_BC_CALL_FLAG_EVALCALL;
61526
61527 comp_ctx->curr_func.may_direct_eval = 1;
61528 }
61529
61530 duk_dup(ctx, left->x1.valstack_idx);
61531 if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
61532 duk__emit_a_b(comp_ctx,
61533 DUK_OP_CSREG,
61534 (duk_regconst_t) (reg_cs + 0),
61535 (duk_regconst_t) reg_varbind);
61536 } else {
61537 duk__emit_a_b(comp_ctx,
61538 DUK_OP_CSVAR,
61539 (duk_regconst_t) (reg_cs + 0),
61540 rc_varname);
61541 }
61542 } else if (left->t == DUK_IVAL_PROP) {
61543 DUK_DDD(DUK_DDDPRINT("function call with property base"));
61544
61545 duk__ispec_toforcedreg(comp_ctx, &left->x1, reg_cs + 0); /* base */
61546 duk__ispec_toforcedreg(comp_ctx, &left->x2, reg_cs + 1); /* key */
61547 duk__emit_a_b_c(comp_ctx,
61548 DUK_OP_CSPROP,
61549 (duk_regconst_t) (reg_cs + 0),
61550 (duk_regconst_t) (reg_cs + 0),
61551 (duk_regconst_t) (reg_cs + 1)); /* in-place setup */
61552 } else {
61553 DUK_DDD(DUK_DDDPRINT("function call with register base"));
61554
61555 duk__ivalue_toforcedreg(comp_ctx, left, reg_cs + 0);
61556 duk__emit_a_b(comp_ctx,
61557 DUK_OP_CSREG,
61558 (duk_regconst_t) (reg_cs + 0),
61559 (duk_regconst_t) (reg_cs + 0)); /* in-place setup */
61560 }
61561
61562 DUK__SETTEMP(comp_ctx, reg_cs + 2);
61563 nargs = duk__parse_arguments(comp_ctx, res); /* parse args starting from "next temp" */
61564
61565 /* Tailcalls are handled by back-patching the TAILCALL flag to the
61566 * already emitted instruction later (in return statement parser).
61567 * Since A and C have a special meaning here, they cannot be "shuffled".
61568 */
61569
61570 duk__emit_a_b_c(comp_ctx,
61571 DUK_OP_CALL | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_C,
61572 (duk_regconst_t) call_flags /*flags*/,
61573 (duk_regconst_t) reg_cs /*basereg*/,
61574 (duk_regconst_t) nargs /*numargs*/);
61575 DUK__SETTEMP(comp_ctx, reg_cs + 1); /* result in csreg */
61576
61577 res->t = DUK_IVAL_PLAIN;
61578 res->x1.t = DUK_ISPEC_REGCONST;
61579 res->x1.regconst = (duk_regconst_t) reg_cs;
61580 return;
61581 }
61582
61583 /* POSTFIX EXPRESSION */
61584
61585 case DUK_TOK_INCREMENT: {
61586 args = (DUK_OP_POSTINCR << 8) + 0;
61587 goto postincdec;
61588 }
61589 case DUK_TOK_DECREMENT: {
61590 args = (DUK_OP_POSTDECR << 8) + 0;
61591 goto postincdec;
61592 }
61593
61594 /* MULTIPLICATIVE EXPRESSION */
61595
61596 case DUK_TOK_MUL: {
61597 args = (DUK_OP_MUL << 8) + DUK__BP_MULTIPLICATIVE; /* UnaryExpression */
61598 goto binary;
61599 }
61600 case DUK_TOK_DIV: {
61601 args = (DUK_OP_DIV << 8) + DUK__BP_MULTIPLICATIVE; /* UnaryExpression */
61602 goto binary;
61603 }
61604 case DUK_TOK_MOD: {
61605 args = (DUK_OP_MOD << 8) + DUK__BP_MULTIPLICATIVE; /* UnaryExpression */
61606 goto binary;
61607 }
61608
61609 /* ADDITIVE EXPRESSION */
61610
61611 case DUK_TOK_ADD: {
61612 args = (DUK_OP_ADD << 8) + DUK__BP_ADDITIVE; /* MultiplicativeExpression */
61613 goto binary;
61614 }
61615 case DUK_TOK_SUB: {
61616 args = (DUK_OP_SUB << 8) + DUK__BP_ADDITIVE; /* MultiplicativeExpression */
61617 goto binary;
61618 }
61619
61620 /* SHIFT EXPRESSION */
61621
61622 case DUK_TOK_ALSHIFT: {
61623 /* << */
61624 args = (DUK_OP_BASL << 8) + DUK__BP_SHIFT;
61625 goto binary;
61626 }
61627 case DUK_TOK_ARSHIFT: {
61628 /* >> */
61629 args = (DUK_OP_BASR << 8) + DUK__BP_SHIFT;
61630 goto binary;
61631 }
61632 case DUK_TOK_RSHIFT: {
61633 /* >>> */
61634 args = (DUK_OP_BLSR << 8) + DUK__BP_SHIFT;
61635 goto binary;
61636 }
61637
61638 /* RELATIONAL EXPRESSION */
61639
61640 case DUK_TOK_LT: {
61641 /* < */
61642 args = (DUK_OP_LT << 8) + DUK__BP_RELATIONAL;
61643 goto binary;
61644 }
61645 case DUK_TOK_GT: {
61646 args = (DUK_OP_GT << 8) + DUK__BP_RELATIONAL;
61647 goto binary;
61648 }
61649 case DUK_TOK_LE: {
61650 args = (DUK_OP_LE << 8) + DUK__BP_RELATIONAL;
61651 goto binary;
61652 }
61653 case DUK_TOK_GE: {
61654 args = (DUK_OP_GE << 8) + DUK__BP_RELATIONAL;
61655 goto binary;
61656 }
61657 case DUK_TOK_INSTANCEOF: {
61658 args = (1 << 16 /*is_extra*/) + (DUK_EXTRAOP_INSTOF << 8) + DUK__BP_RELATIONAL;
61659 goto binary;
61660 }
61661 case DUK_TOK_IN: {
61662 args = (1 << 16 /*is_extra*/) + (DUK_EXTRAOP_IN << 8) + DUK__BP_RELATIONAL;
61663 goto binary;
61664 }
61665
61666 /* EQUALITY EXPRESSION */
61667
61668 case DUK_TOK_EQ: {
61669 args = (DUK_OP_EQ << 8) + DUK__BP_EQUALITY;
61670 goto binary;
61671 }
61672 case DUK_TOK_NEQ: {
61673 args = (DUK_OP_NEQ << 8) + DUK__BP_EQUALITY;
61674 goto binary;
61675 }
61676 case DUK_TOK_SEQ: {
61677 args = (DUK_OP_SEQ << 8) + DUK__BP_EQUALITY;
61678 goto binary;
61679 }
61680 case DUK_TOK_SNEQ: {
61681 args = (DUK_OP_SNEQ << 8) + DUK__BP_EQUALITY;
61682 goto binary;
61683 }
61684
61685 /* BITWISE EXPRESSIONS */
61686
61687 case DUK_TOK_BAND: {
61688 args = (DUK_OP_BAND << 8) + DUK__BP_BAND;
61689 goto binary;
61690 }
61691 case DUK_TOK_BXOR: {
61692 args = (DUK_OP_BXOR << 8) + DUK__BP_BXOR;
61693 goto binary;
61694 }
61695 case DUK_TOK_BOR: {
61696 args = (DUK_OP_BOR << 8) + DUK__BP_BOR;
61697 goto binary;
61698 }
61699
61700 /* LOGICAL EXPRESSIONS */
61701
61702 case DUK_TOK_LAND: {
61703 /* syntactically left-associative but parsed as right-associative */
61704 args = (1 << 8) + DUK__BP_LAND - 1;
61705 goto binary_logical;
61706 }
61707 case DUK_TOK_LOR: {
61708 /* syntactically left-associative but parsed as right-associative */
61709 args = (0 << 8) + DUK__BP_LOR - 1;
61710 goto binary_logical;
61711 }
61712
61713 /* CONDITIONAL EXPRESSION */
61714
61715 case DUK_TOK_QUESTION: {
61716 /* XXX: common reg allocation need is to reuse a sub-expression's temp reg,
61717 * but only if it really is a temp. Nothing fancy here now.
61718 */
61719 duk_reg_t reg_temp;
61720 duk_int_t pc_jump1;
61721 duk_int_t pc_jump2;
61722
61723 reg_temp = DUK__ALLOCTEMP(comp_ctx);
61724 duk__ivalue_toforcedreg(comp_ctx, left, reg_temp);
61725 duk__emit_if_true_skip(comp_ctx, reg_temp);
61726 pc_jump1 = duk__emit_jump_empty(comp_ctx); /* jump to false */
61727 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/); /* AssignmentExpression */
61728 duk__advance_expect(comp_ctx, DUK_TOK_COLON);
61729 pc_jump2 = duk__emit_jump_empty(comp_ctx); /* jump to end */
61730 duk__patch_jump_here(comp_ctx, pc_jump1);
61731 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/); /* AssignmentExpression */
61732 duk__patch_jump_here(comp_ctx, pc_jump2);
61733
61734 DUK__SETTEMP(comp_ctx, reg_temp + 1);
61735 res->t = DUK_IVAL_PLAIN;
61736 res->x1.t = DUK_ISPEC_REGCONST;
61737 res->x1.regconst = (duk_regconst_t) reg_temp;
61738 return;
61739 }
61740
61741 /* ASSIGNMENT EXPRESSION */
61742
61743 case DUK_TOK_EQUALSIGN: {
61744 /*
61745 * Assignments are right associative, allows e.g.
61746 * a = 5;
61747 * a += b = 9; // same as a += (b = 9)
61748 * -> expression value 14, a = 14, b = 9
61749 *
61750 * Right associativiness is reflected in the BP for recursion,
61751 * "-1" ensures assignment operations are allowed.
61752 *
61753 * XXX: just use DUK__BP_COMMA (i.e. no need for 2-step bp levels)?
61754 */
61755 args = (DUK_OP_NONE << 8) + DUK__BP_ASSIGNMENT - 1; /* DUK_OP_NONE marks a 'plain' assignment */
61756 goto assign;
61757 }
61758 case DUK_TOK_ADD_EQ: {
61759 /* right associative */
61760 args = (DUK_OP_ADD << 8) + DUK__BP_ASSIGNMENT - 1;
61761 goto assign;
61762 }
61763 case DUK_TOK_SUB_EQ: {
61764 /* right associative */
61765 args = (DUK_OP_SUB << 8) + DUK__BP_ASSIGNMENT - 1;
61766 goto assign;
61767 }
61768 case DUK_TOK_MUL_EQ: {
61769 /* right associative */
61770 args = (DUK_OP_MUL << 8) + DUK__BP_ASSIGNMENT - 1;
61771 goto assign;
61772 }
61773 case DUK_TOK_DIV_EQ: {
61774 /* right associative */
61775 args = (DUK_OP_DIV << 8) + DUK__BP_ASSIGNMENT - 1;
61776 goto assign;
61777 }
61778 case DUK_TOK_MOD_EQ: {
61779 /* right associative */
61780 args = (DUK_OP_MOD << 8) + DUK__BP_ASSIGNMENT - 1;
61781 goto assign;
61782 }
61783 case DUK_TOK_ALSHIFT_EQ: {
61784 /* right associative */
61785 args = (DUK_OP_BASL << 8) + DUK__BP_ASSIGNMENT - 1;
61786 goto assign;
61787 }
61788 case DUK_TOK_ARSHIFT_EQ: {
61789 /* right associative */
61790 args = (DUK_OP_BASR << 8) + DUK__BP_ASSIGNMENT - 1;
61791 goto assign;
61792 }
61793 case DUK_TOK_RSHIFT_EQ: {
61794 /* right associative */
61795 args = (DUK_OP_BLSR << 8) + DUK__BP_ASSIGNMENT - 1;
61796 goto assign;
61797 }
61798 case DUK_TOK_BAND_EQ: {
61799 /* right associative */
61800 args = (DUK_OP_BAND << 8) + DUK__BP_ASSIGNMENT - 1;
61801 goto assign;
61802 }
61803 case DUK_TOK_BOR_EQ: {
61804 /* right associative */
61805 args = (DUK_OP_BOR << 8) + DUK__BP_ASSIGNMENT - 1;
61806 goto assign;
61807 }
61808 case DUK_TOK_BXOR_EQ: {
61809 /* right associative */
61810 args = (DUK_OP_BXOR << 8) + DUK__BP_ASSIGNMENT - 1;
61811 goto assign;
61812 }
61813
61814 /* COMMA */
61815
61816 case DUK_TOK_COMMA: {
61817 /* right associative */
61818
61819 duk__ivalue_toplain_ignore(comp_ctx, left); /* need side effects, not value */
61820 duk__expr_toplain(comp_ctx, res, DUK__BP_COMMA - 1 /*rbp_flags*/);
61821
61822 /* return 'res' (of right part) as our result */
61823 return;
61824 }
61825
61826 default: {
61827 break;
61828 }
61829 }
61830
61831 DUK_D(DUK_DPRINT("parse error: unexpected token: %ld", (long) tok));
11fdf7f2 61832 DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR);
7c673cae
FG
61833 return;
61834
61835#if 0
61836 /* XXX: shared handling for 'duk__expr_lhs'? */
61837 if (comp_ctx->curr_func.paren_level == 0 && XXX) {
61838 comp_ctx->curr_func.duk__expr_lhs = 0;
61839 }
61840#endif
61841
61842 binary:
61843 /*
61844 * Shared handling of binary operations
61845 *
61846 * args = (is_extraop << 16) + (opcode << 8) + rbp
61847 */
61848 {
61849 duk__ivalue_toplain(comp_ctx, left);
61850 duk__expr_toplain(comp_ctx, res, args & 0xff /*rbp_flags*/);
61851
61852 /* combine left->x1 and res->x1 (right->x1, really) -> (left->x1 OP res->x1) */
61853 DUK_ASSERT(left->t == DUK_IVAL_PLAIN);
61854 DUK_ASSERT(res->t == DUK_IVAL_PLAIN);
61855
61856 res->t = (args >> 16) ? DUK_IVAL_ARITH_EXTRAOP : DUK_IVAL_ARITH;
61857 res->op = (args >> 8) & 0xff;
61858
61859 res->x2.t = res->x1.t;
61860 res->x2.regconst = res->x1.regconst;
61861 duk_copy(ctx, res->x1.valstack_idx, res->x2.valstack_idx);
61862
61863 res->x1.t = left->x1.t;
61864 res->x1.regconst = left->x1.regconst;
61865 duk_copy(ctx, left->x1.valstack_idx, res->x1.valstack_idx);
61866
61867 DUK_DDD(DUK_DDDPRINT("binary op, res: t=%ld, x1.t=%ld, x1.regconst=0x%08lx, x2.t=%ld, x2.regconst=0x%08lx",
61868 (long) res->t, (long) res->x1.t, (unsigned long) res->x1.regconst, (long) res->x2.t, (unsigned long) res->x2.regconst));
61869 return;
61870 }
61871
61872 binary_logical:
61873 /*
61874 * Shared handling for logical AND and logical OR.
61875 *
61876 * args = (truthval << 8) + rbp
61877 *
61878 * Truthval determines when to skip right-hand-side.
61879 * For logical AND truthval=1, for logical OR truthval=0.
61880 *
61881 * See doc/compiler.rst for discussion on compiling logical
61882 * AND and OR expressions. The approach here is very simplistic,
61883 * generating extra jumps and multiple evaluations of truth values,
61884 * but generates code on-the-fly with only local back-patching.
61885 *
61886 * Both logical AND and OR are syntactically left-associated.
61887 * However, logical ANDs are compiled as right associative
61888 * expressions, i.e. "A && B && C" as "A && (B && C)", to allow
61889 * skip jumps to skip over the entire tail. Similarly for logical OR.
61890 */
61891
61892 {
61893 duk_reg_t reg_temp;
61894 duk_int_t pc_jump;
61895 duk_small_uint_t args_truthval = args >> 8;
61896 duk_small_uint_t args_rbp = args & 0xff;
61897
61898 /* XXX: unoptimal use of temps, resetting */
61899
61900 reg_temp = DUK__ALLOCTEMP(comp_ctx);
61901
61902 duk__ivalue_toforcedreg(comp_ctx, left, reg_temp);
61903 duk__emit_a_b(comp_ctx,
61904 DUK_OP_IF | DUK__EMIT_FLAG_NO_SHUFFLE_A,
61905 (duk_regconst_t) args_truthval,
61906 (duk_regconst_t) reg_temp); /* skip jump conditionally */
61907 pc_jump = duk__emit_jump_empty(comp_ctx);
61908 duk__expr_toforcedreg(comp_ctx, res, args_rbp /*rbp_flags*/, reg_temp /*forced_reg*/);
61909 duk__patch_jump_here(comp_ctx, pc_jump);
61910
61911 res->t = DUK_IVAL_PLAIN;
61912 res->x1.t = DUK_ISPEC_REGCONST;
61913 res->x1.regconst = (duk_regconst_t) reg_temp;
61914 return;
61915 }
61916
61917 assign:
61918 /*
61919 * Shared assignment expression handling
61920 *
61921 * args = (opcode << 8) + rbp
61922 *
61923 * If 'opcode' is DUK_OP_NONE, plain assignment without arithmetic.
61924 * Syntactically valid left-hand-side forms which are not accepted as
61925 * left-hand-side values (e.g. as in "f() = 1") must NOT cause a
61926 * SyntaxError, but rather a run-time ReferenceError.
11fdf7f2
TL
61927 *
61928 * When evaluating X <op>= Y, the LHS (X) is conceptually evaluated
61929 * to a temporary first. The RHS is then evaluated. Finally, the
61930 * <op> is applied to the initial value of RHS (not the value after
61931 * RHS evaluation), and written to X. Doing so concretely generates
61932 * inefficient code so we'd like to avoid the temporary when possible.
61933 * See: https://github.com/svaarala/duktape/pull/992.
61934 *
61935 * The expression value (final LHS value, written to RHS) is
61936 * conceptually copied into a fresh temporary so that it won't
61937 * change even if the LHS/RHS values change in outer expressions.
61938 * For example, it'd be generally incorrect for the expression value
61939 * to be the RHS register binding, unless there's a guarantee that it
61940 * won't change during further expression evaluation. Using the
61941 * temporary concretely produces inefficient bytecode, so we try to
61942 * avoid the extra temporary for some known-to-be-safe cases.
61943 * Currently the only safe case we detect is a "top level assignment",
61944 * for example "x = y + z;", where the assignment expression value is
61945 * ignored.
61946 * See: test-dev-assign-expr.js and test-bug-assign-mutate-gh381.js.
7c673cae
FG
61947 */
61948
61949 {
61950 duk_small_uint_t args_op = args >> 8;
61951 duk_small_uint_t args_rbp = args & 0xff;
11fdf7f2 61952 duk_bool_t toplevel_assign;
7c673cae
FG
61953
61954 /* XXX: here we need to know if 'left' is left-hand-side compatible.
61955 * That information is no longer available from current expr parsing
61956 * state; it would need to be carried into the 'left' ivalue or by
61957 * some other means.
61958 */
61959
11fdf7f2
TL
61960 /* A top-level assignment is e.g. "x = y;". For these it's safe
61961 * to use the RHS as-is as the expression value, even if the RHS
61962 * is a reg-bound identifier. The RHS ('res') is right associative
61963 * so it has consumed all other assignment level operations; the
61964 * only relevant lower binding power construct is comma operator
61965 * which will ignore the expression value provided here. Usually
61966 * the top level assignment expression value is ignored, but it
61967 * is relevant for e.g. eval code.
61968 */
61969 toplevel_assign = (comp_ctx->curr_func.nud_count == 1 && /* one token before */
61970 comp_ctx->curr_func.led_count == 1); /* one operator (= assign) */
61971 DUK_DDD(DUK_DDDPRINT("assignment: nud_count=%ld, led_count=%ld, toplevel_assign=%ld",
61972 (long) comp_ctx->curr_func.nud_count,
61973 (long) comp_ctx->curr_func.led_count,
61974 (long) toplevel_assign));
61975
7c673cae
FG
61976 if (left->t == DUK_IVAL_VAR) {
61977 duk_hstring *h_varname;
61978 duk_reg_t reg_varbind;
61979 duk_regconst_t rc_varname;
7c673cae 61980
11fdf7f2 61981 DUK_ASSERT(left->x1.t == DUK_ISPEC_VALUE); /* LHS is already side effect free */
7c673cae
FG
61982
61983 h_varname = duk_get_hstring(ctx, left->x1.valstack_idx);
61984 DUK_ASSERT(h_varname != NULL);
7c673cae 61985 if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
11fdf7f2 61986 /* E5 Section 11.13.1 (and others for other assignments), step 4. */
7c673cae
FG
61987 goto syntax_error_lvalue;
61988 }
7c673cae
FG
61989 duk_dup(ctx, left->x1.valstack_idx);
61990 (void) duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname);
61991
7c673cae 61992 if (args_op == DUK_OP_NONE) {
11fdf7f2
TL
61993 duk__expr(comp_ctx, res, args_rbp /*rbp_flags*/);
61994 if (toplevel_assign) {
61995 /* Any 'res' will do. */
61996 DUK_DDD(DUK_DDDPRINT("plain assignment, toplevel assign, use as is"));
61997 } else {
61998 /* 'res' must be a plain ivalue, and not register-bound variable. */
61999 DUK_DDD(DUK_DDDPRINT("plain assignment, not toplevel assign, ensure not a reg-bound identifier"));
62000 if (res->t != DUK_IVAL_PLAIN || (res->x1.t == DUK_ISPEC_REGCONST &&
62001 (res->x1.regconst & DUK__CONST_MARKER) == 0 &&
62002 !DUK__ISTEMP(comp_ctx, res->x1.regconst))) {
62003 duk__ivalue_totempconst(comp_ctx, res);
62004 }
62005 }
7c673cae 62006 } else {
11fdf7f2
TL
62007 /* For X <op>= Y we need to evaluate the pre-op
62008 * value of X before evaluating the RHS: the RHS
62009 * can change X, but when we do <op> we must use
62010 * the pre-op value.
62011 */
62012 duk_reg_t reg_temp;
62013
7c673cae 62014 reg_temp = DUK__ALLOCTEMP(comp_ctx);
11fdf7f2 62015
7c673cae 62016 if (reg_varbind >= 0) {
11fdf7f2
TL
62017 duk_reg_t reg_res;
62018 duk_reg_t reg_src;
62019 duk_int_t pc_temp_load;
62020 duk_int_t pc_before_rhs;
62021 duk_int_t pc_after_rhs;
62022
62023 if (toplevel_assign) {
62024 /* 'reg_varbind' is the operation result and can also
62025 * become the expression value for top level assignments
62026 * such as: "var x; x += y;".
62027 */
62028 DUK_DD(DUK_DDPRINT("<op>= expression is top level, write directly to reg_varbind"));
62029 reg_res = reg_varbind;
62030 } else {
62031 /* Not safe to use 'reg_varbind' as assignment expression
62032 * value, so go through a temp.
62033 */
62034 DUK_DD(DUK_DDPRINT("<op>= expression is not top level, write to reg_temp"));
62035 reg_res = reg_temp; /* reg_res should be smallest possible */
62036 reg_temp = DUK__ALLOCTEMP(comp_ctx);
62037 }
62038
62039 /* Try to optimize X <op>= Y for reg-bound
62040 * variables. Detect side-effect free RHS
62041 * narrowly by seeing whether it emits code.
62042 * If not, rewind the code emitter and overwrite
62043 * the unnecessary temp reg load.
62044 */
62045
62046 pc_temp_load = duk__get_current_pc(comp_ctx);
62047 duk__emit_a_bc(comp_ctx,
62048 DUK_OP_LDREG,
62049 (duk_regconst_t) reg_temp,
62050 reg_varbind);
62051
62052 pc_before_rhs = duk__get_current_pc(comp_ctx);
62053 duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
62054 DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
62055 pc_after_rhs = duk__get_current_pc(comp_ctx);
62056
62057 DUK_DD(DUK_DDPRINT("pc_temp_load=%ld, pc_before_rhs=%ld, pc_after_rhs=%ld",
62058 (long) pc_temp_load, (long) pc_before_rhs,
62059 (long) pc_after_rhs));
62060
62061 if (pc_after_rhs == pc_before_rhs) {
62062 /* Note: if the reg_temp load generated shuffling
62063 * instructions, we may need to rewind more than
62064 * one instruction, so use explicit PC computation.
62065 */
62066 DUK_DD(DUK_DDPRINT("rhs is side effect free, rewind and avoid unnecessary temp for reg-based <op>="));
62067 DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, (pc_temp_load - pc_before_rhs) * sizeof(duk_compiler_instr));
62068 reg_src = reg_varbind;
62069 } else {
62070 DUK_DD(DUK_DDPRINT("rhs evaluation emitted code, not sure if rhs is side effect free; use temp reg for LHS"));
62071 reg_src = reg_temp;
62072 }
62073
7c673cae
FG
62074 duk__emit_a_b_c(comp_ctx,
62075 args_op,
11fdf7f2
TL
62076 (duk_regconst_t) reg_res,
62077 (duk_regconst_t) reg_src,
7c673cae 62078 res->x1.regconst);
11fdf7f2
TL
62079
62080 res->x1.regconst = (duk_regconst_t) reg_res;
62081
62082 /* Ensure compact use of temps. */
62083 if (DUK__ISTEMP(comp_ctx, reg_res)) {
62084 DUK__SETTEMP(comp_ctx, reg_res + 1);
62085 }
7c673cae 62086 } else {
11fdf7f2
TL
62087 /* When LHS is not register bound, always go through a
62088 * temporary. No optimization for top level assignment.
62089 */
62090
7c673cae
FG
62091 duk__emit_a_bc(comp_ctx,
62092 DUK_OP_GETVAR,
62093 (duk_regconst_t) reg_temp,
62094 rc_varname);
11fdf7f2
TL
62095
62096 duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
62097 DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
62098
7c673cae
FG
62099 duk__emit_a_b_c(comp_ctx,
62100 args_op,
62101 (duk_regconst_t) reg_temp,
62102 (duk_regconst_t) reg_temp,
62103 res->x1.regconst);
11fdf7f2 62104 res->x1.regconst = (duk_regconst_t) reg_temp;
7c673cae 62105 }
11fdf7f2
TL
62106
62107 DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
7c673cae
FG
62108 }
62109
11fdf7f2
TL
62110 /* At this point 'res' holds the potential expression value.
62111 * It can be basically any ivalue here, including a reg-bound
62112 * identifier (if code above deems it safe) or a unary/binary
62113 * operation. Operations must be resolved to a side effect free
62114 * plain value, and the side effects must happen exactly once.
62115 */
62116
7c673cae 62117 if (reg_varbind >= 0) {
11fdf7f2
TL
62118 if (res->t != DUK_IVAL_PLAIN) {
62119 /* Resolve 'res' directly into the LHS binding, and use
62120 * that as the expression value if safe. If not safe,
62121 * resolve to a temp/const and copy to LHS.
62122 */
62123 if (toplevel_assign) {
62124 duk__ivalue_toforcedreg(comp_ctx, res, (duk_int_t) reg_varbind);
62125 } else {
62126 duk__ivalue_totempconst(comp_ctx, res);
62127 duk__copy_ivalue(comp_ctx, res, left); /* use 'left' as a temp */
62128 duk__ivalue_toforcedreg(comp_ctx, left, (duk_int_t) reg_varbind);
62129 }
62130 } else {
62131 /* Use 'res' as the expression value (it's side effect
62132 * free and may be a plain value, a register, or a
62133 * constant) and write it to the LHS binding too.
62134 */
62135 duk__copy_ivalue(comp_ctx, res, left); /* use 'left' as a temp */
62136 duk__ivalue_toforcedreg(comp_ctx, left, (duk_int_t) reg_varbind);
62137 }
7c673cae 62138 } else {
11fdf7f2
TL
62139 /* Only a reg fits into 'A' so coerce 'res' into a register
62140 * for PUTVAR.
7c673cae
FG
62141 *
62142 * XXX: here the current A/B/C split is suboptimal: we could
62143 * just use 9 bits for reg_res (and support constants) and 17
62144 * instead of 18 bits for the varname const index.
62145 */
11fdf7f2
TL
62146
62147 duk__ivalue_toreg(comp_ctx, res);
7c673cae
FG
62148 duk__emit_a_bc(comp_ctx,
62149 DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
11fdf7f2 62150 res->x1.regconst,
7c673cae
FG
62151 rc_varname);
62152 }
62153
11fdf7f2 62154 /* 'res' contains expression value */
7c673cae
FG
62155 } else if (left->t == DUK_IVAL_PROP) {
62156 /* E5 Section 11.13.1 (and others) step 4 never matches for prop writes -> no check */
62157 duk_reg_t reg_obj;
62158 duk_regconst_t rc_key;
62159 duk_regconst_t rc_res;
62160 duk_reg_t reg_temp;
62161
62162 /* Property access expressions ('a[b]') are critical to correct
62163 * LHS evaluation ordering, see test-dev-assign-eval-order*.js.
62164 * We must make sure that the LHS target slot (base object and
62165 * key) don't change during RHS evaluation. The only concrete
62166 * problem is a register reference to a variable-bound register
62167 * (i.e., non-temp). Require temp regs for both key and base.
62168 *
62169 * Don't allow a constant for the object (even for a number
62170 * etc), as it goes into the 'A' field of the opcode.
62171 */
62172
62173 reg_obj = duk__ispec_toregconst_raw(comp_ctx,
62174 &left->x1,
62175 -1 /*forced_reg*/,
62176 DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
62177
62178 rc_key = duk__ispec_toregconst_raw(comp_ctx,
62179 &left->x2,
62180 -1 /*forced_reg*/,
62181 DUK__IVAL_FLAG_REQUIRE_TEMP | DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
62182
62183 /* Evaluate RHS only when LHS is safe. */
7c673cae
FG
62184
62185 if (args_op == DUK_OP_NONE) {
11fdf7f2
TL
62186 duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
62187 DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
7c673cae
FG
62188 rc_res = res->x1.regconst;
62189 } else {
62190 reg_temp = DUK__ALLOCTEMP(comp_ctx);
62191 duk__emit_a_b_c(comp_ctx,
62192 DUK_OP_GETPROP,
62193 (duk_regconst_t) reg_temp,
62194 (duk_regconst_t) reg_obj,
62195 rc_key);
11fdf7f2
TL
62196
62197 duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
62198 DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
62199
7c673cae
FG
62200 duk__emit_a_b_c(comp_ctx,
62201 args_op,
62202 (duk_regconst_t) reg_temp,
62203 (duk_regconst_t) reg_temp,
62204 res->x1.regconst);
62205 rc_res = (duk_regconst_t) reg_temp;
62206 }
62207
62208 duk__emit_a_b_c(comp_ctx,
62209 DUK_OP_PUTPROP | DUK__EMIT_FLAG_A_IS_SOURCE,
62210 (duk_regconst_t) reg_obj,
62211 rc_key,
62212 rc_res);
62213
62214 res->t = DUK_IVAL_PLAIN;
62215 res->x1.t = DUK_ISPEC_REGCONST;
62216 res->x1.regconst = rc_res;
62217 } else {
62218 /* No support for lvalues returned from new or function call expressions.
62219 * However, these must NOT cause compile-time SyntaxErrors, but run-time
62220 * ReferenceErrors. Both left and right sides of the assignment must be
62221 * evaluated before throwing a ReferenceError. For instance:
62222 *
62223 * f() = g();
62224 *
62225 * must result in f() being evaluated, then g() being evaluated, and
62226 * finally, a ReferenceError being thrown. See E5 Section 11.13.1.
62227 */
62228
62229 duk_regconst_t rc_res;
62230
11fdf7f2 62231 /* First evaluate LHS fully to ensure all side effects are out. */
7c673cae
FG
62232 duk__ivalue_toplain_ignore(comp_ctx, left);
62233
11fdf7f2
TL
62234 /* Then evaluate RHS fully (its value becomes the expression value too).
62235 * Technically we'd need the side effect safety check here too, but because
62236 * we always throw using INVLHS the result doesn't matter.
62237 */
7c673cae
FG
62238 rc_res = duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
62239
62240 duk__emit_extraop_only(comp_ctx,
62241 DUK_EXTRAOP_INVLHS);
62242
7c673cae
FG
62243 res->t = DUK_IVAL_PLAIN;
62244 res->x1.t = DUK_ISPEC_REGCONST;
62245 res->x1.regconst = rc_res;
62246 }
62247
62248 return;
62249 }
62250
62251 postincdec:
62252 {
62253 /*
62254 * Post-increment/decrement will return the original value as its
62255 * result value. However, even that value will be coerced using
62256 * ToNumber() which is quite awkward. Specific bytecode opcodes
62257 * are used to handle these semantics.
62258 *
62259 * Note that post increment/decrement has a "no LineTerminator here"
62260 * restriction. This is handled by duk__expr_lbp(), which forcibly terminates
62261 * the previous expression if a LineTerminator occurs before '++'/'--'.
62262 */
62263
62264 duk_reg_t reg_res;
62265 duk_small_uint_t args_op = args >> 8;
62266
62267 /* Specific assumptions for opcode numbering. */
62268 DUK_ASSERT(DUK_OP_POSTINCR + 4 == DUK_OP_POSTINCV);
62269 DUK_ASSERT(DUK_OP_POSTDECR + 4 == DUK_OP_POSTDECV);
62270 DUK_ASSERT(DUK_OP_POSTINCR + 8 == DUK_OP_POSTINCP);
62271 DUK_ASSERT(DUK_OP_POSTDECR + 8 == DUK_OP_POSTDECP);
62272
62273 reg_res = DUK__ALLOCTEMP(comp_ctx);
62274
62275 if (left->t == DUK_IVAL_VAR) {
62276 duk_hstring *h_varname;
62277 duk_reg_t reg_varbind;
62278 duk_regconst_t rc_varname;
62279
62280 h_varname = duk_get_hstring(ctx, left->x1.valstack_idx);
62281 DUK_ASSERT(h_varname != NULL);
62282
62283 if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
62284 goto syntax_error;
62285 }
62286
62287 duk_dup(ctx, left->x1.valstack_idx);
62288 if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
62289 duk__emit_a_bc(comp_ctx,
62290 args_op, /* e.g. DUK_OP_POSTINCR */
62291 (duk_regconst_t) reg_res,
62292 (duk_regconst_t) reg_varbind);
62293 } else {
62294 duk__emit_a_bc(comp_ctx,
62295 args_op + 4, /* e.g. DUK_OP_POSTINCV */
62296 (duk_regconst_t) reg_res,
62297 rc_varname);
62298 }
62299
62300 DUK_DDD(DUK_DDDPRINT("postincdec to '%!O' -> reg_varbind=%ld, rc_varname=%ld",
62301 (duk_heaphdr *) h_varname, (long) reg_varbind, (long) rc_varname));
62302 } else if (left->t == DUK_IVAL_PROP) {
62303 duk_reg_t reg_obj; /* allocate to reg only (not const) */
62304 duk_regconst_t rc_key;
62305
62306 reg_obj = duk__ispec_toregconst_raw(comp_ctx, &left->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
62307 rc_key = duk__ispec_toregconst_raw(comp_ctx, &left->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
62308 duk__emit_a_b_c(comp_ctx,
62309 args_op + 8, /* e.g. DUK_OP_POSTINCP */
62310 (duk_regconst_t) reg_res,
62311 (duk_regconst_t) reg_obj,
62312 rc_key);
62313 } else {
62314 /* Technically return value is not needed because INVLHS will
62315 * unconditially throw a ReferenceError. Coercion is necessary
62316 * for proper semantics (consider ToNumber() called for an object).
62317 * Use DUK_EXTRAOP_UNP with a dummy register to get ToNumber().
62318 */
62319 duk__ivalue_toforcedreg(comp_ctx, left, reg_res);
62320 duk__emit_extraop_bc(comp_ctx,
62321 DUK_EXTRAOP_UNP,
62322 reg_res); /* for side effects, result ignored */
62323 duk__emit_extraop_only(comp_ctx,
62324 DUK_EXTRAOP_INVLHS);
62325 }
62326
62327 res->t = DUK_IVAL_PLAIN;
62328 res->x1.t = DUK_ISPEC_REGCONST;
62329 res->x1.regconst = (duk_regconst_t) reg_res;
62330 DUK__SETTEMP(comp_ctx, reg_res + 1);
62331 return;
62332 }
62333
62334 syntax_error:
11fdf7f2 62335 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_EXPRESSION);
7c673cae
FG
62336 return;
62337
62338 syntax_error_lvalue:
11fdf7f2 62339 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LVALUE);
7c673cae
FG
62340 return;
62341}
62342
62343DUK_LOCAL duk_small_uint_t duk__expr_lbp(duk_compiler_ctx *comp_ctx) {
62344 duk_small_int_t tok = comp_ctx->curr_token.t;
62345
62346 DUK_ASSERT(tok >= DUK_TOK_MINVAL && tok <= DUK_TOK_MAXVAL);
62347 DUK_ASSERT(sizeof(duk__token_lbp) == DUK_TOK_MAXVAL + 1);
62348
62349 /* XXX: integrate support for this into led() instead?
62350 * Similar issue as post-increment/post-decrement.
62351 */
62352
62353 /* prevent duk__expr_led() by using a binding power less than anything valid */
62354 if (tok == DUK_TOK_IN && !comp_ctx->curr_func.allow_in) {
62355 return 0;
62356 }
62357
62358 if ((tok == DUK_TOK_DECREMENT || tok == DUK_TOK_INCREMENT) &&
62359 (comp_ctx->curr_token.lineterm)) {
62360 /* '++' or '--' in a post-increment/decrement position,
62361 * and a LineTerminator occurs between the operator and
62362 * the preceding expression. Force the previous expr
62363 * to terminate, in effect treating e.g. "a,b\n++" as
62364 * "a,b;++" (= SyntaxError).
62365 */
62366 return 0;
62367 }
62368
62369 return DUK__TOKEN_LBP_GET_BP(duk__token_lbp[tok]); /* format is bit packed */
62370}
62371
62372/*
62373 * Expression parsing.
62374 *
62375 * Upon entry to 'expr' and its variants, 'curr_tok' is assumed to be the
62376 * first token of the expression. Upon exit, 'curr_tok' will be the first
62377 * token not part of the expression (e.g. semicolon terminating an expression
62378 * statement).
62379 */
62380
62381#define DUK__EXPR_RBP_MASK 0xff
11fdf7f2
TL
62382#define DUK__EXPR_FLAG_REJECT_IN (1 << 8) /* reject 'in' token (used for for-in) */
62383#define DUK__EXPR_FLAG_ALLOW_EMPTY (1 << 9) /* allow empty expression */
62384#define DUK__EXPR_FLAG_REQUIRE_INIT (1 << 10) /* require initializer for var/const */
7c673cae
FG
62385
62386/* main expression parser function */
62387DUK_LOCAL void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
62388 duk_hthread *thr = comp_ctx->thr;
62389 duk_context *ctx = (duk_context *) thr;
62390 duk_ivalue tmp_alloc; /* 'res' is used for "left", and 'tmp' for "right" */
62391 duk_ivalue *tmp = &tmp_alloc;
62392 duk_small_uint_t rbp;
62393
62394 DUK__RECURSION_INCREASE(comp_ctx, thr);
62395
62396 duk_require_stack(ctx, DUK__PARSE_EXPR_SLOTS);
62397
62398 /* filter out flags from exprtop rbp_flags here to save space */
62399 rbp = rbp_flags & DUK__EXPR_RBP_MASK;
62400
62401 DUK_DDD(DUK_DDDPRINT("duk__expr(), rbp_flags=%ld, rbp=%ld, allow_in=%ld, paren_level=%ld",
62402 (long) rbp_flags, (long) rbp, (long) comp_ctx->curr_func.allow_in,
62403 (long) comp_ctx->curr_func.paren_level));
62404
62405 DUK_MEMZERO(&tmp_alloc, sizeof(tmp_alloc));
62406 tmp->x1.valstack_idx = duk_get_top(ctx);
62407 tmp->x2.valstack_idx = tmp->x1.valstack_idx + 1;
62408 duk_push_undefined(ctx);
62409 duk_push_undefined(ctx);
62410
62411 /* XXX: where to release temp regs in intermediate expressions?
62412 * e.g. 1+2+3 -> don't inflate temp register count when parsing this.
62413 * that particular expression temp regs can be forced here.
62414 */
62415
62416 /* XXX: increase ctx->expr_tokens here for every consumed token
62417 * (this would be a nice statistic)?
62418 */
62419
62420 if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON || comp_ctx->curr_token.t == DUK_TOK_RPAREN) {
62421 /* XXX: possibly incorrect handling of empty expression */
62422 DUK_DDD(DUK_DDDPRINT("empty expression"));
62423 if (!(rbp_flags & DUK__EXPR_FLAG_ALLOW_EMPTY)) {
11fdf7f2 62424 DUK_ERROR_SYNTAX(thr, DUK_STR_EMPTY_EXPR_NOT_ALLOWED);
7c673cae
FG
62425 }
62426 res->t = DUK_IVAL_PLAIN;
62427 res->x1.t = DUK_ISPEC_VALUE;
62428 duk_push_undefined(ctx);
62429 duk_replace(ctx, res->x1.valstack_idx);
62430 goto cleanup;
62431 }
62432
62433 duk__advance(comp_ctx);
62434 duk__expr_nud(comp_ctx, res); /* reuse 'res' as 'left' */
62435 while (rbp < duk__expr_lbp(comp_ctx)) {
62436 duk__advance(comp_ctx);
62437 duk__expr_led(comp_ctx, res, tmp);
62438 duk__copy_ivalue(comp_ctx, tmp, res); /* tmp -> res */
62439 }
62440
62441 cleanup:
62442 /* final result is already in 'res' */
62443
62444 duk_pop_2(ctx);
62445
62446 DUK__RECURSION_DECREASE(comp_ctx, thr);
62447}
62448
62449DUK_LOCAL void duk__exprtop(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
62450 duk_hthread *thr = comp_ctx->thr;
62451
62452 /* Note: these variables must reside in 'curr_func' instead of the global
62453 * context: when parsing function expressions, expression parsing is nested.
62454 */
62455 comp_ctx->curr_func.nud_count = 0;
62456 comp_ctx->curr_func.led_count = 0;
62457 comp_ctx->curr_func.paren_level = 0;
62458 comp_ctx->curr_func.expr_lhs = 1;
62459 comp_ctx->curr_func.allow_in = (rbp_flags & DUK__EXPR_FLAG_REJECT_IN ? 0 : 1);
62460
62461 duk__expr(comp_ctx, res, rbp_flags);
62462
62463 if (!(rbp_flags & DUK__EXPR_FLAG_ALLOW_EMPTY) && duk__expr_is_empty(comp_ctx)) {
11fdf7f2 62464 DUK_ERROR_SYNTAX(thr, DUK_STR_EMPTY_EXPR_NOT_ALLOWED);
7c673cae
FG
62465 }
62466}
62467
62468/* A bunch of helpers (for size optimization) that combine duk__expr()/duk__exprtop()
62469 * and result conversions.
62470 *
62471 * Each helper needs at least 2-3 calls to make it worth while to wrap.
62472 */
62473
11fdf7f2 62474#if 0 /* unused */
7c673cae
FG
62475DUK_LOCAL duk_reg_t duk__expr_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
62476 duk__expr(comp_ctx, res, rbp_flags);
62477 return duk__ivalue_toreg(comp_ctx, res);
62478}
11fdf7f2 62479#endif
7c673cae
FG
62480
62481#if 0 /* unused */
11fdf7f2 62482DUK_LOCAL duk_reg_t duk__expr_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
7c673cae 62483 duk__expr(comp_ctx, res, rbp_flags);
11fdf7f2 62484 return duk__ivalue_totemp(comp_ctx, res);
7c673cae
FG
62485}
62486#endif
62487
62488DUK_LOCAL void duk__expr_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_reg_t forced_reg) {
62489 DUK_ASSERT(forced_reg >= 0);
62490 duk__expr(comp_ctx, res, rbp_flags);
62491 duk__ivalue_toforcedreg(comp_ctx, res, forced_reg);
62492}
62493
62494DUK_LOCAL duk_regconst_t duk__expr_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
62495 duk__expr(comp_ctx, res, rbp_flags);
62496 return duk__ivalue_toregconst(comp_ctx, res);
62497}
62498
11fdf7f2
TL
62499#if 0 /* unused */
62500DUK_LOCAL duk_regconst_t duk__expr_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
62501 duk__expr(comp_ctx, res, rbp_flags);
62502 return duk__ivalue_totempconst(comp_ctx, res);
62503}
62504#endif
62505
7c673cae
FG
62506DUK_LOCAL void duk__expr_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
62507 duk__expr(comp_ctx, res, rbp_flags);
62508 duk__ivalue_toplain(comp_ctx, res);
62509}
62510
62511DUK_LOCAL void duk__expr_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
62512 duk__expr(comp_ctx, res, rbp_flags);
62513 duk__ivalue_toplain_ignore(comp_ctx, res);
62514}
62515
62516DUK_LOCAL duk_reg_t duk__exprtop_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
62517 duk__exprtop(comp_ctx, res, rbp_flags);
62518 return duk__ivalue_toreg(comp_ctx, res);
62519}
62520
62521#if 0 /* unused */
11fdf7f2 62522DUK_LOCAL duk_reg_t duk__exprtop_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
7c673cae 62523 duk__exprtop(comp_ctx, res, rbp_flags);
11fdf7f2 62524 return duk__ivalue_totemp(comp_ctx, res);
7c673cae
FG
62525}
62526#endif
62527
62528DUK_LOCAL void duk__exprtop_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_reg_t forced_reg) {
62529 DUK_ASSERT(forced_reg >= 0);
62530 duk__exprtop(comp_ctx, res, rbp_flags);
62531 duk__ivalue_toforcedreg(comp_ctx, res, forced_reg);
62532}
62533
62534DUK_LOCAL duk_regconst_t duk__exprtop_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
62535 duk__exprtop(comp_ctx, res, rbp_flags);
62536 return duk__ivalue_toregconst(comp_ctx, res);
62537}
62538
62539#if 0 /* unused */
62540DUK_LOCAL void duk__exprtop_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags) {
62541 duk__exprtop(comp_ctx, res, rbp_flags);
62542 duk__ivalue_toplain_ignore(comp_ctx, res);
62543}
62544#endif
62545
62546/*
62547 * Parse an individual source element (top level statement) or a statement.
62548 *
62549 * Handles labeled statements automatically (peeling away labels before
62550 * parsing an expression that follows the label(s)).
62551 *
62552 * Upon entry, 'curr_tok' contains the first token of the statement (parsed
62553 * in "allow regexp literal" mode). Upon exit, 'curr_tok' contains the first
62554 * token following the statement (if the statement has a terminator, this is
62555 * the token after the terminator).
62556 */
62557
62558#ifdef DUK__HAS_VAL
62559#undef DUK__HAS_VAL
62560#endif
62561#ifdef DUK__HAS_TERM
62562#undef DUK__HAS_TERM
62563#endif
62564#ifdef DUK__ALLOW_AUTO_SEMI_ALWAYS
62565#undef DUK__ALLOW_AUTO_SEMI_ALWAYS
62566#endif
62567#ifdef DUK__STILL_PROLOGUE
62568#undef DUK__STILL_PROLOGUE
62569#endif
62570#ifdef DUK__IS_TERMINAL
62571#undef DUK__IS_TERMINAL
62572#endif
62573
62574#define DUK__HAS_VAL (1 << 0) /* stmt has non-empty value */
62575#define DUK__HAS_TERM (1 << 1) /* stmt has explicit/implicit semicolon terminator */
62576#define DUK__ALLOW_AUTO_SEMI_ALWAYS (1 << 2) /* allow automatic semicolon even without lineterm (compatibility) */
62577#define DUK__STILL_PROLOGUE (1 << 3) /* statement does not terminate directive prologue */
62578#define DUK__IS_TERMINAL (1 << 4) /* statement is guaranteed to be terminal (control doesn't flow to next statement) */
62579
62580/* Parse a single variable declaration (e.g. "i" or "i=10"). A leading 'var'
62581 * has already been eaten. These is no return value in 'res', it is used only
62582 * as a temporary.
62583 *
62584 * When called from 'for-in' statement parser, the initializer expression must
62585 * not allow the 'in' token. The caller supply additional expression parsing
62586 * flags (like DUK__EXPR_FLAG_REJECT_IN) in 'expr_flags'.
62587 *
62588 * Finally, out_rc_varname and out_reg_varbind are updated to reflect where
62589 * the identifier is bound:
62590 *
62591 * If register bound: out_reg_varbind >= 0, out_rc_varname == 0 (ignore)
62592 * If not register bound: out_reg_varbind < 0, out_rc_varname >= 0
62593 *
62594 * These allow the caller to use the variable for further assignment, e.g.
62595 * as is done in 'for-in' parsing.
62596 */
62597
62598DUK_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) {
62599 duk_hthread *thr = comp_ctx->thr;
62600 duk_context *ctx = (duk_context *) thr;
62601 duk_hstring *h_varname;
62602 duk_reg_t reg_varbind;
62603 duk_regconst_t rc_varname;
62604
62605 /* assume 'var' has been eaten */
62606
62607 /* Note: Identifier rejects reserved words */
62608 if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) {
62609 goto syntax_error;
62610 }
62611 h_varname = comp_ctx->curr_token.str1;
62612
62613 DUK_ASSERT(h_varname != NULL);
62614
62615 /* strict mode restrictions (E5 Section 12.2.1) */
62616 if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
62617 goto syntax_error;
62618 }
62619
62620 /* register declarations in first pass */
62621 if (comp_ctx->curr_func.in_scanning) {
62622 duk_uarridx_t n;
62623 DUK_DDD(DUK_DDDPRINT("register variable declaration %!O in pass 1",
62624 (duk_heaphdr *) h_varname));
62625 n = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.decls_idx);
62626 duk_push_hstring(ctx, h_varname);
62627 duk_put_prop_index(ctx, comp_ctx->curr_func.decls_idx, n);
62628 duk_push_int(ctx, DUK_DECL_TYPE_VAR + (0 << 8));
62629 duk_put_prop_index(ctx, comp_ctx->curr_func.decls_idx, n + 1);
62630 }
62631
62632 duk_push_hstring(ctx, h_varname); /* push before advancing to keep reachable */
62633
62634 /* register binding lookup is based on varmap (even in first pass) */
62635 duk_dup_top(ctx);
62636 (void) duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname);
62637
62638 duk__advance(comp_ctx); /* eat identifier */
62639
62640 if (comp_ctx->curr_token.t == DUK_TOK_EQUALSIGN) {
62641 duk__advance(comp_ctx);
62642
62643 DUK_DDD(DUK_DDDPRINT("vardecl, assign to '%!O' -> reg_varbind=%ld, rc_varname=%ld",
62644 (duk_heaphdr *) h_varname, (long) reg_varbind, (long) rc_varname));
62645
62646 duk__exprtop(comp_ctx, res, DUK__BP_COMMA | expr_flags /*rbp_flags*/); /* AssignmentExpression */
62647
62648 if (reg_varbind >= 0) {
62649 duk__ivalue_toforcedreg(comp_ctx, res, reg_varbind);
62650 } else {
62651 duk_reg_t reg_val;
62652 reg_val = duk__ivalue_toreg(comp_ctx, res);
62653 duk__emit_a_bc(comp_ctx,
62654 DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
62655 (duk_regconst_t) reg_val,
62656 rc_varname);
62657 }
11fdf7f2
TL
62658 } else {
62659 if (expr_flags & DUK__EXPR_FLAG_REQUIRE_INIT) {
62660 /* Used for minimal 'const': initializer required. */
62661 goto syntax_error;
62662 }
7c673cae
FG
62663 }
62664
62665 duk_pop(ctx); /* pop varname */
62666
62667 *out_rc_varname = rc_varname;
62668 *out_reg_varbind = reg_varbind;
62669
62670 return;
62671
62672 syntax_error:
11fdf7f2 62673 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_VAR_DECLARATION);
7c673cae
FG
62674}
62675
11fdf7f2 62676DUK_LOCAL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags) {
7c673cae
FG
62677 duk_reg_t reg_varbind;
62678 duk_regconst_t rc_varname;
62679
62680 duk__advance(comp_ctx); /* eat 'var' */
62681
62682 for (;;) {
62683 /* rc_varname and reg_varbind are ignored here */
11fdf7f2 62684 duk__parse_var_decl(comp_ctx, res, 0 | expr_flags, &reg_varbind, &rc_varname);
7c673cae
FG
62685
62686 if (comp_ctx->curr_token.t != DUK_TOK_COMMA) {
62687 break;
62688 }
62689 duk__advance(comp_ctx);
62690 }
62691}
62692
62693DUK_LOCAL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
62694 duk_hthread *thr = comp_ctx->thr;
62695 duk_context *ctx = (duk_context *) thr;
62696 duk_int_t pc_v34_lhs; /* start variant 3/4 left-hand-side code (L1 in doc/compiler.rst example) */
62697 duk_reg_t temp_reset; /* knock back "next temp" to this whenever possible */
62698 duk_reg_t reg_temps; /* preallocated temporaries (2) for variants 3 and 4 */
62699
62700 DUK_DDD(DUK_DDDPRINT("start parsing a for/for-in statement"));
62701
62702 /* Two temporaries are preallocated here for variants 3 and 4 which need
62703 * registers which are never clobbered by expressions in the loop
62704 * (concretely: for the enumerator object and the next enumerated value).
62705 * Variants 1 and 2 "release" these temps.
62706 */
62707
62708 reg_temps = DUK__ALLOCTEMPS(comp_ctx, 2);
62709
62710 temp_reset = DUK__GETTEMP(comp_ctx);
62711
62712 /*
62713 * For/for-in main variants are:
62714 *
62715 * 1. for (ExpressionNoIn_opt; Expression_opt; Expression_opt) Statement
62716 * 2. for (var VariableDeclarationNoIn; Expression_opt; Expression_opt) Statement
62717 * 3. for (LeftHandSideExpression in Expression) Statement
62718 * 4. for (var VariableDeclarationNoIn in Expression) Statement
62719 *
62720 * Parsing these without arbitrary lookahead or backtracking is relatively
62721 * tricky but we manage to do so for now.
62722 *
62723 * See doc/compiler.rst for a detailed discussion of control flow
62724 * issues, evaluation order issues, etc.
62725 */
62726
62727 duk__advance(comp_ctx); /* eat 'for' */
62728 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
62729
62730 DUK_DDD(DUK_DDDPRINT("detecting for/for-in loop variant, pc=%ld", (long) duk__get_current_pc(comp_ctx)));
62731
62732 /* a label site has been emitted by duk__parse_stmt() automatically
62733 * (it will also emit the ENDLABEL).
62734 */
62735
62736 if (comp_ctx->curr_token.t == DUK_TOK_VAR) {
62737 /*
62738 * Variant 2 or 4
62739 */
62740
62741 duk_reg_t reg_varbind; /* variable binding register if register-bound (otherwise < 0) */
62742 duk_regconst_t rc_varname; /* variable name reg/const, if variable not register-bound */
62743
62744 duk__advance(comp_ctx); /* eat 'var' */
62745 duk__parse_var_decl(comp_ctx, res, DUK__EXPR_FLAG_REJECT_IN, &reg_varbind, &rc_varname);
62746 DUK__SETTEMP(comp_ctx, temp_reset);
62747
62748 if (comp_ctx->curr_token.t == DUK_TOK_IN) {
62749 /*
62750 * Variant 4
62751 */
62752
62753 DUK_DDD(DUK_DDDPRINT("detected for variant 4: for (var VariableDeclarationNoIn in Expression) Statement"));
62754 pc_v34_lhs = duk__get_current_pc(comp_ctx); /* jump is inserted here */
62755 if (reg_varbind >= 0) {
62756 duk__emit_a_bc(comp_ctx,
62757 DUK_OP_LDREG,
62758 (duk_regconst_t) reg_varbind,
62759 (duk_regconst_t) (reg_temps + 0));
62760 } else {
62761 duk__emit_a_bc(comp_ctx,
62762 DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
62763 (duk_regconst_t) (reg_temps + 0),
62764 rc_varname);
62765 }
62766 goto parse_3_or_4;
62767 } else {
62768 /*
62769 * Variant 2
62770 */
62771
62772 DUK_DDD(DUK_DDDPRINT("detected for variant 2: for (var VariableDeclarationNoIn; Expression_opt; Expression_opt) Statement"));
62773 for (;;) {
62774 /* more initializers */
62775 if (comp_ctx->curr_token.t != DUK_TOK_COMMA) {
62776 break;
62777 }
62778 DUK_DDD(DUK_DDDPRINT("variant 2 has another variable initializer"));
62779
62780 duk__advance(comp_ctx); /* eat comma */
62781 duk__parse_var_decl(comp_ctx, res, DUK__EXPR_FLAG_REJECT_IN, &reg_varbind, &rc_varname);
62782 }
62783 goto parse_1_or_2;
62784 }
62785 } else {
62786 /*
62787 * Variant 1 or 3
62788 */
62789
62790 pc_v34_lhs = duk__get_current_pc(comp_ctx); /* jump is inserted here (variant 3) */
62791
62792 /* Note that duk__exprtop() here can clobber any reg above current temp_next,
62793 * so any loop variables (e.g. enumerator) must be "preallocated".
62794 */
62795
62796 /* don't coerce yet to a plain value (variant 3 needs special handling) */
62797 duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR | DUK__EXPR_FLAG_REJECT_IN | DUK__EXPR_FLAG_ALLOW_EMPTY /*rbp_flags*/); /* Expression */
62798 if (comp_ctx->curr_token.t == DUK_TOK_IN) {
62799 /*
62800 * Variant 3
62801 */
62802
62803 /* XXX: need to determine LHS type, and check that it is LHS compatible */
62804 DUK_DDD(DUK_DDDPRINT("detected for variant 3: for (LeftHandSideExpression in Expression) Statement"));
62805 if (duk__expr_is_empty(comp_ctx)) {
62806 goto syntax_error; /* LeftHandSideExpression does not allow empty expression */
62807 }
62808
62809 if (res->t == DUK_IVAL_VAR) {
62810 duk_reg_t reg_varbind;
62811 duk_regconst_t rc_varname;
62812
62813 duk_dup(ctx, res->x1.valstack_idx);
62814 if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
62815 duk__emit_a_bc(comp_ctx,
62816 DUK_OP_LDREG,
62817 (duk_regconst_t) reg_varbind,
62818 (duk_regconst_t) (reg_temps + 0));
62819 } else {
62820 duk__emit_a_bc(comp_ctx,
62821 DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
62822 (duk_regconst_t) (reg_temps + 0),
62823 rc_varname);
62824 }
62825 } else if (res->t == DUK_IVAL_PROP) {
62826 /* Don't allow a constant for the object (even for a number etc), as
62827 * it goes into the 'A' field of the opcode.
62828 */
62829 duk_reg_t reg_obj;
62830 duk_regconst_t rc_key;
62831 reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
62832 rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
62833 duk__emit_a_b_c(comp_ctx,
62834 DUK_OP_PUTPROP | DUK__EMIT_FLAG_A_IS_SOURCE,
62835 (duk_regconst_t) reg_obj,
62836 rc_key,
62837 (duk_regconst_t) (reg_temps + 0));
62838 } else {
62839 duk__ivalue_toplain_ignore(comp_ctx, res); /* just in case */
62840 duk__emit_extraop_only(comp_ctx,
62841 DUK_EXTRAOP_INVLHS);
62842 }
62843 goto parse_3_or_4;
62844 } else {
62845 /*
62846 * Variant 1
62847 */
62848
62849 DUK_DDD(DUK_DDDPRINT("detected for variant 1: for (ExpressionNoIn_opt; Expression_opt; Expression_opt) Statement"));
62850 duk__ivalue_toplain_ignore(comp_ctx, res);
62851 goto parse_1_or_2;
62852 }
62853 }
62854
62855 parse_1_or_2:
62856 /*
62857 * Parse variant 1 or 2. The first part expression (which differs
62858 * in the variants) has already been parsed and its code emitted.
62859 *
62860 * reg_temps + 0: unused
62861 * reg_temps + 1: unused
62862 */
62863 {
62864 duk_regconst_t rc_cond;
62865 duk_int_t pc_l1, pc_l2, pc_l3, pc_l4;
62866 duk_int_t pc_jumpto_l3, pc_jumpto_l4;
62867 duk_bool_t expr_c_empty;
62868
62869 DUK_DDD(DUK_DDDPRINT("shared code for parsing variants 1 and 2"));
62870
62871 /* "release" preallocated temps since we won't need them */
62872 temp_reset = reg_temps + 0;
62873 DUK__SETTEMP(comp_ctx, temp_reset);
62874
62875 duk__advance_expect(comp_ctx, DUK_TOK_SEMICOLON);
62876
62877 pc_l1 = duk__get_current_pc(comp_ctx);
62878 duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR | DUK__EXPR_FLAG_ALLOW_EMPTY /*rbp_flags*/); /* Expression_opt */
62879 if (duk__expr_is_empty(comp_ctx)) {
62880 /* no need to coerce */
62881 pc_jumpto_l3 = duk__emit_jump_empty(comp_ctx); /* to body */
62882 pc_jumpto_l4 = -1; /* omitted */
62883 } else {
62884 rc_cond = duk__ivalue_toregconst(comp_ctx, res);
62885 duk__emit_if_false_skip(comp_ctx, rc_cond);
62886 pc_jumpto_l3 = duk__emit_jump_empty(comp_ctx); /* to body */
62887 pc_jumpto_l4 = duk__emit_jump_empty(comp_ctx); /* to exit */
62888 }
62889 DUK__SETTEMP(comp_ctx, temp_reset);
62890
62891 duk__advance_expect(comp_ctx, DUK_TOK_SEMICOLON);
62892
62893 pc_l2 = duk__get_current_pc(comp_ctx);
62894 duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR | DUK__EXPR_FLAG_ALLOW_EMPTY /*rbp_flags*/); /* Expression_opt */
62895 if (duk__expr_is_empty(comp_ctx)) {
62896 /* no need to coerce */
62897 expr_c_empty = 1;
62898 /* JUMP L1 omitted */
62899 } else {
62900 duk__ivalue_toplain_ignore(comp_ctx, res);
62901 expr_c_empty = 0;
62902 duk__emit_jump(comp_ctx, pc_l1);
62903 }
62904 DUK__SETTEMP(comp_ctx, temp_reset);
62905
62906 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
62907
62908 pc_l3 = duk__get_current_pc(comp_ctx);
62909 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
62910 if (expr_c_empty) {
62911 duk__emit_jump(comp_ctx, pc_l1);
62912 } else {
62913 duk__emit_jump(comp_ctx, pc_l2);
62914 }
62915 /* temp reset is not necessary after duk__parse_stmt(), which already does it */
62916
62917 pc_l4 = duk__get_current_pc(comp_ctx);
62918
62919 DUK_DDD(DUK_DDDPRINT("patching jumps: jumpto_l3: %ld->%ld, jumpto_l4: %ld->%ld, "
62920 "break: %ld->%ld, continue: %ld->%ld",
62921 (long) pc_jumpto_l3, (long) pc_l3, (long) pc_jumpto_l4, (long) pc_l4,
62922 (long) (pc_label_site + 1), (long) pc_l4, (long) (pc_label_site + 2), (long) pc_l2));
62923
62924 duk__patch_jump(comp_ctx, pc_jumpto_l3, pc_l3);
62925 duk__patch_jump(comp_ctx, pc_jumpto_l4, pc_l4);
62926 duk__patch_jump(comp_ctx,
62927 pc_label_site + 1,
62928 pc_l4); /* break jump */
62929 duk__patch_jump(comp_ctx,
62930 pc_label_site + 2,
62931 expr_c_empty ? pc_l1 : pc_l2); /* continue jump */
62932 }
62933 goto finished;
62934
62935 parse_3_or_4:
62936 /*
62937 * Parse variant 3 or 4.
62938 *
62939 * For variant 3 (e.g. "for (A in C) D;") the code for A (except the
62940 * final property/variable write) has already been emitted. The first
62941 * instruction of that code is at pc_v34_lhs; a JUMP needs to be inserted
62942 * there to satisfy control flow needs.
62943 *
62944 * For variant 4, if the variable declaration had an initializer
62945 * (e.g. "for (var A = B in C) D;") the code for the assignment
62946 * (B) has already been emitted.
62947 *
62948 * Variables set before entering here:
62949 *
62950 * pc_v34_lhs: insert a "JUMP L2" here (see doc/compiler.rst example).
62951 * reg_temps + 0: iteration target value (written to LHS)
62952 * reg_temps + 1: enumerator object
62953 */
62954 {
62955 duk_int_t pc_l1, pc_l2, pc_l3, pc_l4, pc_l5;
62956 duk_int_t pc_jumpto_l2, pc_jumpto_l3, pc_jumpto_l4, pc_jumpto_l5;
62957 duk_reg_t reg_target;
62958
62959 DUK_DDD(DUK_DDDPRINT("shared code for parsing variants 3 and 4, pc_v34_lhs=%ld", (long) pc_v34_lhs));
62960
62961 DUK__SETTEMP(comp_ctx, temp_reset);
62962
62963 /* First we need to insert a jump in the middle of previously
62964 * emitted code to get the control flow right. No jumps can
62965 * cross the position where the jump is inserted. See doc/compiler.rst
62966 * for discussion on the intricacies of control flow and side effects
62967 * for variants 3 and 4.
62968 */
62969
62970 duk__insert_jump_entry(comp_ctx, pc_v34_lhs);
62971 pc_jumpto_l2 = pc_v34_lhs; /* inserted jump */
62972 pc_l1 = pc_v34_lhs + 1; /* +1, right after inserted jump */
62973
62974 /* The code for writing reg_temps + 0 to the left hand side has already
62975 * been emitted.
62976 */
62977
62978 pc_jumpto_l3 = duk__emit_jump_empty(comp_ctx); /* -> loop body */
62979
62980 duk__advance(comp_ctx); /* eat 'in' */
62981
62982 /* Parse enumeration target and initialize enumerator. For 'null' and 'undefined',
62983 * INITENUM will creates a 'null' enumerator which works like an empty enumerator
62984 * (E5 Section 12.6.4, step 3). Note that INITENUM requires the value to be in a
62985 * register (constant not allowed).
62986 */
62987
62988 pc_l2 = duk__get_current_pc(comp_ctx);
62989 reg_target = duk__exprtop_toreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); /* Expression */
62990 duk__emit_extraop_b_c(comp_ctx,
62991 DUK_EXTRAOP_INITENUM | DUK__EMIT_FLAG_B_IS_TARGET,
62992 (duk_regconst_t) (reg_temps + 1),
62993 (duk_regconst_t) reg_target);
62994 pc_jumpto_l4 = duk__emit_jump_empty(comp_ctx);
62995 DUK__SETTEMP(comp_ctx, temp_reset);
62996
62997 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
62998
62999 pc_l3 = duk__get_current_pc(comp_ctx);
63000 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
63001 /* temp reset is not necessary after duk__parse_stmt(), which already does it */
63002
63003 /* NEXTENUM needs a jump slot right after the main opcode.
63004 * We need the code emitter to reserve the slot: if there's
63005 * target shuffling, the target shuffle opcodes must happen
63006 * after the jump slot (for NEXTENUM the shuffle opcodes are
63007 * not needed if the enum is finished).
63008 */
63009 pc_l4 = duk__get_current_pc(comp_ctx);
63010 duk__emit_extraop_b_c(comp_ctx,
63011 DUK_EXTRAOP_NEXTENUM | DUK__EMIT_FLAG_B_IS_TARGET | DUK__EMIT_FLAG_RESERVE_JUMPSLOT,
63012 (duk_regconst_t) (reg_temps + 0),
63013 (duk_regconst_t) (reg_temps + 1));
63014 pc_jumpto_l5 = comp_ctx->emit_jumpslot_pc; /* NEXTENUM jump slot: executed when enum finished */
63015 duk__emit_jump(comp_ctx, pc_l1); /* jump to next loop, using reg_v34_iter as iterated value */
63016
63017 pc_l5 = duk__get_current_pc(comp_ctx);
63018
63019 /* XXX: since the enumerator may be a memory expensive object,
63020 * perhaps clear it explicitly here? If so, break jump must
63021 * go through this clearing operation.
63022 */
63023
63024 DUK_DDD(DUK_DDDPRINT("patching jumps: jumpto_l2: %ld->%ld, jumpto_l3: %ld->%ld, "
63025 "jumpto_l4: %ld->%ld, jumpto_l5: %ld->%ld, "
63026 "break: %ld->%ld, continue: %ld->%ld",
63027 (long) pc_jumpto_l2, (long) pc_l2, (long) pc_jumpto_l3, (long) pc_l3,
63028 (long) pc_jumpto_l4, (long) pc_l4, (long) pc_jumpto_l5, (long) pc_l5,
63029 (long) (pc_label_site + 1), (long) pc_l5, (long) (pc_label_site + 2), (long) pc_l4));
63030
63031 duk__patch_jump(comp_ctx, pc_jumpto_l2, pc_l2);
63032 duk__patch_jump(comp_ctx, pc_jumpto_l3, pc_l3);
63033 duk__patch_jump(comp_ctx, pc_jumpto_l4, pc_l4);
63034 duk__patch_jump(comp_ctx, pc_jumpto_l5, pc_l5);
63035 duk__patch_jump(comp_ctx, pc_label_site + 1, pc_l5); /* break jump */
63036 duk__patch_jump(comp_ctx, pc_label_site + 2, pc_l4); /* continue jump */
63037 }
63038 goto finished;
63039
63040 finished:
63041 DUK_DDD(DUK_DDDPRINT("end parsing a for/for-in statement"));
63042 return;
63043
63044 syntax_error:
11fdf7f2 63045 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_FOR);
7c673cae
FG
63046}
63047
63048DUK_LOCAL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
63049 duk_hthread *thr = comp_ctx->thr;
63050 duk_reg_t temp_at_loop;
63051 duk_regconst_t rc_switch; /* reg/const for switch value */
63052 duk_regconst_t rc_case; /* reg/const for case value */
63053 duk_reg_t reg_temp; /* general temp register */
63054 duk_int_t pc_prevcase = -1;
63055 duk_int_t pc_prevstmt = -1;
63056 duk_int_t pc_default = -1; /* -1 == not set, -2 == pending (next statement list) */
63057
63058 /* Note: negative pc values are ignored when patching jumps, so no explicit checks needed */
63059
63060 /*
63061 * Switch is pretty complicated because of several conflicting concerns:
63062 *
63063 * - Want to generate code without an intermediate representation,
63064 * i.e., in one go
63065 *
63066 * - Case selectors are expressions, not values, and may thus e.g. throw
63067 * exceptions (which causes evaluation order concerns)
63068 *
63069 * - Evaluation semantics of case selectors and default clause need to be
63070 * carefully implemented to provide correct behavior even with case value
63071 * side effects
63072 *
63073 * - Fall through case and default clauses; avoiding dead JUMPs if case
63074 * ends with an unconditional jump (a break or a continue)
63075 *
63076 * - The same case value may occur multiple times, but evaluation rules
63077 * only process the first match before switching to a "propagation" mode
63078 * where case values are no longer evaluated
63079 *
63080 * See E5 Section 12.11. Also see doc/compiler.rst for compilation
63081 * discussion.
63082 */
63083
63084 duk__advance(comp_ctx);
63085 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
63086 rc_switch = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
63087 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
63088 duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
63089
63090 DUK_DDD(DUK_DDDPRINT("switch value in register %ld", (long) rc_switch));
63091
63092 temp_at_loop = DUK__GETTEMP(comp_ctx);
63093
63094 for (;;) {
63095 duk_int_t num_stmts;
63096 duk_small_int_t tok;
63097
63098 /* sufficient for keeping temp reg numbers in check */
63099 DUK__SETTEMP(comp_ctx, temp_at_loop);
63100
63101 if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
63102 break;
63103 }
63104
63105 /*
63106 * Parse a case or default clause.
63107 */
63108
63109 if (comp_ctx->curr_token.t == DUK_TOK_CASE) {
63110 /*
63111 * Case clause.
63112 *
63113 * Note: cannot use reg_case as a temp register (for SEQ target)
63114 * because it may be a constant.
63115 */
63116
63117 duk__patch_jump_here(comp_ctx, pc_prevcase); /* chain jumps for case
63118 * evaluation and checking
63119 */
63120
63121 duk__advance(comp_ctx);
63122 rc_case = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
63123 duk__advance_expect(comp_ctx, DUK_TOK_COLON);
63124
63125 reg_temp = DUK__ALLOCTEMP(comp_ctx);
63126 duk__emit_a_b_c(comp_ctx,
63127 DUK_OP_SEQ,
63128 (duk_regconst_t) reg_temp,
63129 rc_switch,
63130 rc_case);
63131 duk__emit_if_true_skip(comp_ctx, (duk_regconst_t) reg_temp);
63132
63133 /* jump to next case clause */
63134 pc_prevcase = duk__emit_jump_empty(comp_ctx); /* no match, next case */
63135
63136 /* statements go here (if any) on next loop */
63137 } else if (comp_ctx->curr_token.t == DUK_TOK_DEFAULT) {
63138 /*
63139 * Default clause.
63140 */
63141
63142 if (pc_default >= 0) {
63143 goto syntax_error;
63144 }
63145 duk__advance(comp_ctx);
63146 duk__advance_expect(comp_ctx, DUK_TOK_COLON);
63147
63148 /* Fix for https://github.com/svaarala/duktape/issues/155:
63149 * If 'default' is first clause (detected by pc_prevcase < 0)
63150 * we need to ensure we stay in the matching chain.
63151 */
63152 if (pc_prevcase < 0) {
63153 DUK_DD(DUK_DDPRINT("default clause is first, emit prevcase jump"));
63154 pc_prevcase = duk__emit_jump_empty(comp_ctx);
63155 }
63156
63157 /* default clause matches next statement list (if any) */
63158 pc_default = -2;
63159 } else {
63160 /* Code is not accepted before the first case/default clause */
63161 goto syntax_error;
63162 }
63163
63164 /*
63165 * Parse code after the clause. Possible terminators are
63166 * 'case', 'default', and '}'.
63167 *
63168 * Note that there may be no code at all, not even an empty statement,
63169 * between case clauses. This must be handled just like an empty statement
63170 * (omitting seemingly pointless JUMPs), to avoid situations like
63171 * test-bug-case-fallthrough.js.
63172 */
63173
63174 num_stmts = 0;
63175 if (pc_default == -2) {
63176 pc_default = duk__get_current_pc(comp_ctx);
63177 }
63178
63179 /* Note: this is correct even for default clause statements:
63180 * they participate in 'fall-through' behavior even if the
63181 * default clause is in the middle.
63182 */
63183 duk__patch_jump_here(comp_ctx, pc_prevstmt); /* chain jumps for 'fall-through'
63184 * after a case matches.
63185 */
63186
63187 for (;;) {
63188 tok = comp_ctx->curr_token.t;
63189 if (tok == DUK_TOK_CASE || tok == DUK_TOK_DEFAULT ||
63190 tok == DUK_TOK_RCURLY) {
63191 break;
63192 }
63193 num_stmts++;
63194 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
63195 }
63196
63197 /* fall-through jump to next code of next case (backpatched) */
63198 pc_prevstmt = duk__emit_jump_empty(comp_ctx);
63199
63200 /* XXX: would be nice to omit this jump when the jump is not
63201 * reachable, at least in the obvious cases (such as the case
63202 * ending with a 'break'.
63203 *
63204 * Perhaps duk__parse_stmt() could provide some info on whether
63205 * the statement is a "dead end"?
63206 *
63207 * If implemented, just set pc_prevstmt to -1 when not needed.
63208 */
63209 }
63210
63211 DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RCURLY);
63212 duk__advance(comp_ctx);
63213
63214 /* default case control flow patchup; note that if pc_prevcase < 0
63215 * (i.e. no case clauses), control enters default case automatically.
63216 */
63217 if (pc_default >= 0) {
63218 /* default case exists: go there if no case matches */
63219 duk__patch_jump(comp_ctx, pc_prevcase, pc_default);
63220 } else {
63221 /* default case does not exist, or no statements present
63222 * after default case: finish case evaluation
63223 */
63224 duk__patch_jump_here(comp_ctx, pc_prevcase);
63225 }
63226
63227 /* fall-through control flow patchup; note that pc_prevstmt may be
63228 * < 0 (i.e. no case clauses), in which case this is a no-op.
63229 */
63230 duk__patch_jump_here(comp_ctx, pc_prevstmt);
63231
63232 /* continue jump not patched, an INVALID opcode remains there */
63233 duk__patch_jump_here(comp_ctx, pc_label_site + 1); /* break jump */
63234
63235 /* Note: 'fast' breaks will jump to pc_label_site + 1, which will
63236 * then jump here. The double jump will be eliminated by a
63237 * peephole pass, resulting in an optimal jump here. The label
63238 * site jumps will remain in bytecode and will waste code size.
63239 */
63240
63241 return;
63242
63243 syntax_error:
11fdf7f2 63244 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_SWITCH);
7c673cae
FG
63245}
63246
63247DUK_LOCAL void duk__parse_if_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
63248 duk_reg_t temp_reset;
63249 duk_regconst_t rc_cond;
63250 duk_int_t pc_jump_false;
63251
63252 DUK_DDD(DUK_DDDPRINT("begin parsing if statement"));
63253
63254 temp_reset = DUK__GETTEMP(comp_ctx);
63255
63256 duk__advance(comp_ctx); /* eat 'if' */
63257 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
63258
63259 rc_cond = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
63260 duk__emit_if_true_skip(comp_ctx, rc_cond);
63261 pc_jump_false = duk__emit_jump_empty(comp_ctx); /* jump to end or else part */
63262 DUK__SETTEMP(comp_ctx, temp_reset);
63263
63264 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
63265
63266 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
63267
63268 /* The 'else' ambiguity is resolved by 'else' binding to the innermost
63269 * construct, so greedy matching is correct here.
63270 */
63271
63272 if (comp_ctx->curr_token.t == DUK_TOK_ELSE) {
63273 duk_int_t pc_jump_end;
63274
63275 DUK_DDD(DUK_DDDPRINT("if has else part"));
63276
63277 duk__advance(comp_ctx);
63278
63279 pc_jump_end = duk__emit_jump_empty(comp_ctx); /* jump from true part to end */
63280 duk__patch_jump_here(comp_ctx, pc_jump_false);
63281
63282 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
63283
63284 duk__patch_jump_here(comp_ctx, pc_jump_end);
63285 } else {
63286 DUK_DDD(DUK_DDDPRINT("if does not have else part"));
63287
63288 duk__patch_jump_here(comp_ctx, pc_jump_false);
63289 }
63290
63291 DUK_DDD(DUK_DDDPRINT("end parsing if statement"));
63292}
63293
63294DUK_LOCAL void duk__parse_do_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
63295 duk_regconst_t rc_cond;
63296 duk_int_t pc_start;
63297
63298 DUK_DDD(DUK_DDDPRINT("begin parsing do statement"));
63299
63300 duk__advance(comp_ctx); /* eat 'do' */
63301
63302 pc_start = duk__get_current_pc(comp_ctx);
63303 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
63304 duk__patch_jump_here(comp_ctx, pc_label_site + 2); /* continue jump */
63305
63306 duk__advance_expect(comp_ctx, DUK_TOK_WHILE);
63307 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
63308
63309 rc_cond = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
63310 duk__emit_if_false_skip(comp_ctx, rc_cond);
63311 duk__emit_jump(comp_ctx, pc_start);
63312 /* no need to reset temps, as we're finished emitting code */
63313
63314 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
63315
63316 duk__patch_jump_here(comp_ctx, pc_label_site + 1); /* break jump */
63317
63318 DUK_DDD(DUK_DDDPRINT("end parsing do statement"));
63319}
63320
63321DUK_LOCAL void duk__parse_while_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
63322 duk_reg_t temp_reset;
63323 duk_regconst_t rc_cond;
63324 duk_int_t pc_start;
63325 duk_int_t pc_jump_false;
63326
63327 DUK_DDD(DUK_DDDPRINT("begin parsing while statement"));
63328
63329 temp_reset = DUK__GETTEMP(comp_ctx);
63330
63331 duk__advance(comp_ctx); /* eat 'while' */
63332
63333 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
63334
63335 pc_start = duk__get_current_pc(comp_ctx);
63336 duk__patch_jump_here(comp_ctx, pc_label_site + 2); /* continue jump */
63337
63338 rc_cond = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
63339 duk__emit_if_true_skip(comp_ctx, rc_cond);
63340 pc_jump_false = duk__emit_jump_empty(comp_ctx);
63341 DUK__SETTEMP(comp_ctx, temp_reset);
63342
63343 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
63344
63345 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
63346 duk__emit_jump(comp_ctx, pc_start);
63347
63348 duk__patch_jump_here(comp_ctx, pc_jump_false);
63349 duk__patch_jump_here(comp_ctx, pc_label_site + 1); /* break jump */
63350
63351 DUK_DDD(DUK_DDDPRINT("end parsing while statement"));
63352}
63353
63354DUK_LOCAL void duk__parse_break_or_continue_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
63355 duk_hthread *thr = comp_ctx->thr;
63356 duk_bool_t is_break = (comp_ctx->curr_token.t == DUK_TOK_BREAK);
63357 duk_int_t label_id;
63358 duk_int_t label_catch_depth;
63359 duk_int_t label_pc; /* points to LABEL; pc+1 = jump site for break; pc+2 = jump site for continue */
63360 duk_bool_t label_is_closest;
63361
63362 DUK_UNREF(res);
63363
63364 duk__advance(comp_ctx); /* eat 'break' or 'continue' */
63365
63366 if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON || /* explicit semi follows */
63367 comp_ctx->curr_token.lineterm || /* automatic semi will be inserted */
63368 comp_ctx->curr_token.allow_auto_semi) { /* automatic semi will be inserted */
63369 /* break/continue without label */
63370
63371 duk__lookup_active_label(comp_ctx, DUK_HTHREAD_STRING_EMPTY_STRING(thr), is_break, &label_id, &label_catch_depth, &label_pc, &label_is_closest);
63372 } else if (comp_ctx->curr_token.t == DUK_TOK_IDENTIFIER) {
63373 /* break/continue with label (label cannot be a reserved word, production is 'Identifier' */
63374 DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
63375 duk__lookup_active_label(comp_ctx, comp_ctx->curr_token.str1, is_break, &label_id, &label_catch_depth, &label_pc, &label_is_closest);
63376 duk__advance(comp_ctx);
63377 } else {
11fdf7f2 63378 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_BREAK_CONT_LABEL);
7c673cae
FG
63379 }
63380
63381 /* Use a fast break/continue when possible. A fast break/continue is
63382 * just a jump to the LABEL break/continue jump slot, which then jumps
63383 * to an appropriate place (for break, going through ENDLABEL correctly).
63384 * The peephole optimizer will optimize the jump to a direct one.
63385 */
63386
63387 if (label_catch_depth == comp_ctx->curr_func.catch_depth &&
63388 label_is_closest) {
63389 DUK_DDD(DUK_DDDPRINT("break/continue: is_break=%ld, label_id=%ld, label_is_closest=%ld, "
63390 "label_catch_depth=%ld, catch_depth=%ld "
63391 "-> use fast variant (direct jump)",
63392 (long) is_break, (long) label_id, (long) label_is_closest,
63393 (long) label_catch_depth, (long) comp_ctx->curr_func.catch_depth));
63394
63395 duk__emit_jump(comp_ctx, label_pc + (is_break ? 1 : 2));
63396 } else {
63397 DUK_DDD(DUK_DDDPRINT("break/continue: is_break=%ld, label_id=%ld, label_is_closest=%ld, "
63398 "label_catch_depth=%ld, catch_depth=%ld "
63399 "-> use slow variant (longjmp)",
63400 (long) is_break, (long) label_id, (long) label_is_closest,
63401 (long) label_catch_depth, (long) comp_ctx->curr_func.catch_depth));
63402
63403 duk__emit_extraop_bc(comp_ctx,
63404 is_break ? DUK_EXTRAOP_BREAK : DUK_EXTRAOP_CONTINUE,
63405 (duk_regconst_t) label_id);
63406 }
63407}
63408
63409DUK_LOCAL void duk__parse_return_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
63410 duk_hthread *thr = comp_ctx->thr;
63411 duk_regconst_t rc_val;
63412 duk_small_uint_t ret_flags;
63413
63414 duk__advance(comp_ctx); /* eat 'return' */
63415
63416 /* A 'return' statement is only allowed inside an actual function body,
63417 * not as part of eval or global code.
63418 */
63419 if (!comp_ctx->curr_func.is_function) {
11fdf7f2 63420 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_RETURN);
7c673cae
FG
63421 }
63422
7c673cae
FG
63423 ret_flags = 0;
63424
63425 if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON || /* explicit semi follows */
63426 comp_ctx->curr_token.lineterm || /* automatic semi will be inserted */
63427 comp_ctx->curr_token.allow_auto_semi) { /* automatic semi will be inserted */
63428 DUK_DDD(DUK_DDDPRINT("empty return value -> undefined"));
63429 rc_val = 0;
63430 } else {
63431 duk_int_t pc_before_expr;
63432 duk_int_t pc_after_expr;
63433
63434 DUK_DDD(DUK_DDDPRINT("return with a value"));
63435
63436 DUK_UNREF(pc_before_expr);
63437 DUK_UNREF(pc_after_expr);
63438
63439 pc_before_expr = duk__get_current_pc(comp_ctx);
63440 rc_val = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
63441 pc_after_expr = duk__get_current_pc(comp_ctx);
63442
63443 /* Tail call check: if last opcode emitted was CALL(I), and
63444 * the context allows it, change the CALL(I) to a tail call.
63445 * This doesn't guarantee that a tail call will be allowed at
63446 * runtime, so the RETURN must still be emitted. (Duktape
63447 * 0.10.0 avoided this and simulated a RETURN if a tail call
63448 * couldn't be used at runtime; but this didn't work
63449 * correctly with a thread yield/resume, see
63450 * test-bug-tailcall-thread-yield-resume.js for discussion.)
63451 *
63452 * In addition to the last opcode being CALL, we also need to
63453 * be sure that 'rc_val' is the result register of the CALL(I).
63454 * For instance, for the expression 'return 0, (function ()
63455 * { return 1; }), 2' the last opcode emitted is CALL (no
63456 * bytecode is emitted for '2') but 'rc_val' indicates
63457 * constant '2'. Similarly if '2' is replaced by a register
63458 * bound variable, no opcodes are emitted but tail call would
63459 * be incorrect.
63460 *
63461 * This is tricky and easy to get wrong. It would be best to
63462 * track enough expression metadata to check that 'rc_val' came
63463 * from that last CALL instruction. We don't have that metadata
63464 * now, so we check that 'rc_val' is a temporary register result
63465 * (not a constant or a register bound variable). There should
63466 * be no way currently for 'rc_val' to be a temporary for an
63467 * expression following the CALL instruction without emitting
63468 * some opcodes following the CALL. This proxy check is used
63469 * below.
63470 *
63471 * See: test-bug-comma-expr-gh131.js.
63472 *
63473 * The non-standard 'caller' property disables tail calls
63474 * because they pose some special cases which haven't been
63475 * fixed yet.
63476 */
63477
63478#if defined(DUK_USE_TAILCALL)
63479 if (comp_ctx->curr_func.catch_depth == 0 && /* no catchers */
63480 pc_after_expr > pc_before_expr) { /* at least one opcode emitted */
63481 duk_compiler_instr *instr;
63482 duk_small_uint_t op;
63483
63484 instr = duk__get_instr_ptr(comp_ctx, pc_after_expr - 1);
63485 DUK_ASSERT(instr != NULL);
63486
63487 op = (duk_small_uint_t) DUK_DEC_OP(instr->ins);
63488 if ((op == DUK_OP_CALL || op == DUK_OP_CALLI) &&
63489 DUK__ISTEMP(comp_ctx, rc_val) /* see above */) {
63490 DUK_DDD(DUK_DDDPRINT("return statement detected a tail call opportunity: "
63491 "catch depth is 0, duk__exprtop() emitted >= 1 instructions, "
63492 "and last instruction is a CALL "
63493 "-> set TAILCALL flag"));
63494 /* Just flip the single bit. */
63495 instr->ins |= DUK_ENC_OP_A_B_C(0, DUK_BC_CALL_FLAG_TAILCALL, 0, 0);
63496 }
63497 }
63498#endif /* DUK_USE_TAILCALL */
63499
63500 ret_flags = DUK_BC_RETURN_FLAG_HAVE_RETVAL;
63501 }
63502
7c673cae
FG
63503 duk__emit_a_b(comp_ctx,
63504 DUK_OP_RETURN | DUK__EMIT_FLAG_NO_SHUFFLE_A,
63505 (duk_regconst_t) ret_flags /*flags*/,
63506 rc_val /*reg*/);
63507}
63508
63509DUK_LOCAL void duk__parse_throw_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
63510 duk_reg_t reg_val;
63511
63512 duk__advance(comp_ctx); /* eat 'throw' */
63513
63514 /* Unlike break/continue, throw statement does not allow an empty value. */
63515
63516 if (comp_ctx->curr_token.lineterm) {
11fdf7f2 63517 DUK_ERROR_SYNTAX(comp_ctx->thr, DUK_STR_INVALID_THROW);
7c673cae
FG
63518 }
63519
63520 reg_val = duk__exprtop_toreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
63521 duk__emit_extraop_bc(comp_ctx,
63522 DUK_EXTRAOP_THROW,
63523 (duk_regconst_t) reg_val);
63524}
63525
63526DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
63527 duk_hthread *thr = comp_ctx->thr;
63528 duk_context *ctx = (duk_context *) thr;
63529 duk_reg_t reg_catch; /* reg_catch+0 and reg_catch+1 are reserved for TRYCATCH */
63530 duk_regconst_t rc_varname = 0;
63531 duk_small_uint_t trycatch_flags = 0;
63532 duk_int_t pc_ldconst = -1;
63533 duk_int_t pc_trycatch = -1;
63534 duk_int_t pc_catch = -1;
63535 duk_int_t pc_finally = -1;
63536
63537 DUK_UNREF(res);
63538
63539 /*
63540 * See the following documentation for discussion:
63541 *
63542 * doc/execution.rst: control flow details
63543 *
63544 * Try, catch, and finally "parts" are Blocks, not Statements, so
63545 * they must always be delimited by curly braces. This is unlike e.g.
63546 * the if statement, which accepts any Statement. This eliminates any
63547 * questions of matching parts of nested try statements. The Block
63548 * parsing is implemented inline here (instead of calling out).
63549 *
63550 * Finally part has a 'let scoped' variable, which requires a few kinks
63551 * here.
63552 */
63553
63554 comp_ctx->curr_func.catch_depth++;
63555
63556 duk__advance(comp_ctx); /* eat 'try' */
63557
63558 reg_catch = DUK__ALLOCTEMPS(comp_ctx, 2);
63559
63560 /* The target for this LDCONST may need output shuffling, but we assume
63561 * that 'pc_ldconst' will be the LDCONST that we can patch later. This
63562 * should be the case because there's no input shuffling. (If there's
63563 * no catch clause, this LDCONST will be replaced with a NOP.)
63564 */
63565 pc_ldconst = duk__get_current_pc(comp_ctx);
63566 duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, reg_catch, 0 /*patched later*/);
63567
63568 pc_trycatch = duk__get_current_pc(comp_ctx);
63569 duk__emit_invalid(comp_ctx); /* TRYCATCH, cannot emit now (not enough info) */
63570 duk__emit_invalid(comp_ctx); /* jump for 'catch' case */
63571 duk__emit_invalid(comp_ctx); /* jump for 'finally' case or end (if no finally) */
63572
63573 /* try part */
63574 duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
63575 duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
63576 /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
63577 duk__emit_extraop_only(comp_ctx,
63578 DUK_EXTRAOP_ENDTRY);
63579
63580 if (comp_ctx->curr_token.t == DUK_TOK_CATCH) {
63581 /*
63582 * The catch variable must be updated to reflect the new allocated
63583 * register for the duration of the catch clause. We need to store
63584 * and restore the original value for the varmap entry (if any).
63585 */
63586
63587 /*
63588 * Note: currently register bindings must be fixed for the entire
63589 * function. So, even though the catch variable is in a register
63590 * we know, we must use an explicit environment record and slow path
63591 * accesses to read/write the catch binding to make closures created
63592 * within the catch clause work correctly. This restriction should
63593 * be fixable (at least in common cases) later.
63594 *
63595 * See: test-bug-catch-binding-2.js.
63596 *
63597 * XXX: improve to get fast path access to most catch clauses.
63598 */
63599
63600 duk_hstring *h_var;
63601 duk_int_t varmap_value; /* for storing/restoring the varmap binding for catch variable */
63602
63603 DUK_DDD(DUK_DDDPRINT("stack top at start of catch clause: %ld", (long) duk_get_top(ctx)));
63604
63605 trycatch_flags |= DUK_BC_TRYCATCH_FLAG_HAVE_CATCH;
63606
63607 pc_catch = duk__get_current_pc(comp_ctx);
63608
63609 duk__advance(comp_ctx);
63610 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
63611
63612 if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) {
63613 /* Identifier, i.e. don't allow reserved words */
63614 goto syntax_error;
63615 }
63616 h_var = comp_ctx->curr_token.str1;
63617 DUK_ASSERT(h_var != NULL);
63618
63619 duk_push_hstring(ctx, h_var); /* keep in on valstack, use borrowed ref below */
63620
63621 if (comp_ctx->curr_func.is_strict &&
63622 ((h_var == DUK_HTHREAD_STRING_EVAL(thr)) ||
63623 (h_var == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)))) {
63624 DUK_DDD(DUK_DDDPRINT("catch identifier 'eval' or 'arguments' in strict mode -> SyntaxError"));
63625 goto syntax_error;
63626 }
63627
63628 duk_dup_top(ctx);
63629 rc_varname = duk__getconst(comp_ctx);
63630 DUK_DDD(DUK_DDDPRINT("catch clause, rc_varname=0x%08lx (%ld)",
63631 (unsigned long) rc_varname, (long) rc_varname));
63632
63633 duk__advance(comp_ctx);
63634 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
63635
63636 duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
63637
63638 DUK_DDD(DUK_DDDPRINT("varmap before modifying for catch clause: %!iT",
63639 (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx)));
63640
63641 duk_dup_top(ctx);
63642 duk_get_prop(ctx, comp_ctx->curr_func.varmap_idx);
63643 if (duk_is_undefined(ctx, -1)) {
63644 varmap_value = -2;
63645 } else if (duk_is_null(ctx, -1)) {
63646 varmap_value = -1;
63647 } else {
63648 DUK_ASSERT(duk_is_number(ctx, -1));
63649 varmap_value = duk_get_int(ctx, -1);
63650 DUK_ASSERT(varmap_value >= 0);
63651 }
63652 duk_pop(ctx);
63653
63654#if 0
63655 /* It'd be nice to do something like this - but it doesn't
63656 * work for closures created inside the catch clause.
63657 */
63658 duk_dup_top(ctx);
63659 duk_push_int(ctx, (duk_int_t) (reg_catch + 0));
63660 duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx);
63661#endif
63662 duk_dup_top(ctx);
63663 duk_push_null(ctx);
63664 duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx);
63665
63666 duk__emit_a_bc(comp_ctx,
63667 DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
63668 (duk_regconst_t) (reg_catch + 0) /*value*/,
63669 rc_varname /*varname*/);
63670
63671 DUK_DDD(DUK_DDDPRINT("varmap before parsing catch clause: %!iT",
63672 (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx)));
63673
63674 duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
63675 /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
63676
63677 if (varmap_value == -2) {
63678 /* not present */
63679 duk_del_prop(ctx, comp_ctx->curr_func.varmap_idx);
63680 } else {
63681 if (varmap_value == -1) {
63682 duk_push_null(ctx);
63683 } else {
63684 DUK_ASSERT(varmap_value >= 0);
63685 duk_push_int(ctx, varmap_value);
63686 }
63687 duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx);
63688 }
63689 /* varname is popped by above code */
63690
63691 DUK_DDD(DUK_DDDPRINT("varmap after restore catch clause: %!iT",
63692 (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx)));
63693
63694 duk__emit_extraop_only(comp_ctx,
63695 DUK_EXTRAOP_ENDCATCH);
63696
63697 /*
63698 * XXX: for now, indicate that an expensive catch binding
63699 * declarative environment is always needed. If we don't
63700 * need it, we don't need the const_varname either.
63701 */
63702
63703 trycatch_flags |= DUK_BC_TRYCATCH_FLAG_CATCH_BINDING;
63704
63705 DUK_DDD(DUK_DDDPRINT("stack top at end of catch clause: %ld", (long) duk_get_top(ctx)));
63706 }
63707
63708 if (comp_ctx->curr_token.t == DUK_TOK_FINALLY) {
63709 trycatch_flags |= DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY;
63710
63711 pc_finally = duk__get_current_pc(comp_ctx);
63712
63713 duk__advance(comp_ctx);
63714
63715 duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
63716 duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
63717 /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
63718 duk__emit_extraop_b(comp_ctx,
63719 DUK_EXTRAOP_ENDFIN,
63720 reg_catch); /* rethrow */
63721 }
63722
63723 if (!(trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) &&
63724 !(trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY)) {
63725 /* must have catch and/or finally */
63726 goto syntax_error;
63727 }
63728
63729 /* If there's no catch block, rc_varname will be 0 and duk__patch_trycatch()
63730 * will replace the LDCONST with a NOP. For any actual constant (including
63731 * constant 0) the DUK__CONST_MARKER flag will be set in rc_varname.
63732 */
63733
63734 duk__patch_trycatch(comp_ctx,
63735 pc_ldconst,
63736 pc_trycatch,
63737 reg_catch,
63738 rc_varname,
63739 trycatch_flags);
63740
63741 if (trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) {
63742 DUK_ASSERT(pc_catch >= 0);
63743 duk__patch_jump(comp_ctx, pc_trycatch + 1, pc_catch);
63744 }
63745
63746 if (trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY) {
63747 DUK_ASSERT(pc_finally >= 0);
63748 duk__patch_jump(comp_ctx, pc_trycatch + 2, pc_finally);
63749 } else {
63750 /* without finally, the second jump slot is used to jump to end of stmt */
63751 duk__patch_jump_here(comp_ctx, pc_trycatch + 2);
63752 }
63753
63754 comp_ctx->curr_func.catch_depth--;
63755 return;
63756
63757 syntax_error:
11fdf7f2 63758 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_TRY);
7c673cae
FG
63759}
63760
63761DUK_LOCAL void duk__parse_with_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
63762 duk_int_t pc_trycatch;
63763 duk_int_t pc_finished;
63764 duk_reg_t reg_catch;
63765 duk_small_uint_t trycatch_flags;
63766
63767 if (comp_ctx->curr_func.is_strict) {
11fdf7f2 63768 DUK_ERROR_SYNTAX(comp_ctx->thr, DUK_STR_WITH_IN_STRICT_MODE);
7c673cae
FG
63769 }
63770
63771 comp_ctx->curr_func.catch_depth++;
63772
63773 duk__advance(comp_ctx); /* eat 'with' */
63774
63775 reg_catch = DUK__ALLOCTEMPS(comp_ctx, 2);
63776
63777 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
63778 duk__exprtop_toforcedreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/, reg_catch);
63779 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
63780
63781 pc_trycatch = duk__get_current_pc(comp_ctx);
63782 trycatch_flags = DUK_BC_TRYCATCH_FLAG_WITH_BINDING;
63783 duk__emit_a_bc(comp_ctx,
63784 DUK_OP_TRYCATCH | DUK__EMIT_FLAG_NO_SHUFFLE_A,
63785 (duk_regconst_t) trycatch_flags /*a*/,
63786 (duk_regconst_t) reg_catch /*bc*/);
63787 duk__emit_invalid(comp_ctx); /* catch jump */
63788 duk__emit_invalid(comp_ctx); /* finished jump */
63789
63790 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
63791 duk__emit_extraop_only(comp_ctx,
63792 DUK_EXTRAOP_ENDTRY);
63793
63794 pc_finished = duk__get_current_pc(comp_ctx);
63795
63796 duk__patch_jump(comp_ctx, pc_trycatch + 2, pc_finished);
63797
63798 comp_ctx->curr_func.catch_depth--;
63799}
63800
63801DUK_LOCAL duk_int_t duk__stmt_label_site(duk_compiler_ctx *comp_ctx, duk_int_t label_id) {
63802 /* if a site already exists, nop: max one label site per statement */
63803 if (label_id >= 0) {
63804 return label_id;
63805 }
63806
63807 label_id = comp_ctx->curr_func.label_next++;
63808 DUK_DDD(DUK_DDDPRINT("allocated new label id for label site: %ld", (long) label_id));
63809
63810 duk__emit_extraop_bc(comp_ctx,
63811 DUK_EXTRAOP_LABEL,
63812 (duk_regconst_t) label_id);
63813 duk__emit_invalid(comp_ctx);
63814 duk__emit_invalid(comp_ctx);
63815
63816 return label_id;
63817}
63818
63819/* Parse a single statement.
63820 *
63821 * Creates a label site (with an empty label) automatically for iteration
63822 * statements. Also "peels off" any label statements for explicit labels.
63823 */
63824DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_bool_t allow_source_elem) {
63825 duk_hthread *thr = comp_ctx->thr;
63826 duk_context *ctx = (duk_context *) thr;
63827 duk_bool_t dir_prol_at_entry; /* directive prologue status at entry */
63828 duk_reg_t temp_at_entry;
63829 duk_uarridx_t labels_len_at_entry;
63830 duk_int_t pc_at_entry; /* assumed to also be PC of "LABEL" */
63831 duk_int_t stmt_id;
63832 duk_small_uint_t stmt_flags = 0;
63833 duk_int_t label_id = -1;
63834 duk_small_uint_t tok;
63835
63836 DUK__RECURSION_INCREASE(comp_ctx, thr);
63837
63838 temp_at_entry = DUK__GETTEMP(comp_ctx);
63839 pc_at_entry = duk__get_current_pc(comp_ctx);
63840 labels_len_at_entry = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.labelnames_idx);
63841 stmt_id = comp_ctx->curr_func.stmt_next++;
63842 dir_prol_at_entry = comp_ctx->curr_func.in_directive_prologue;
63843
63844 DUK_UNREF(stmt_id);
63845
63846 DUK_DDD(DUK_DDDPRINT("parsing a statement, stmt_id=%ld, temp_at_entry=%ld, labels_len_at_entry=%ld, "
63847 "is_strict=%ld, in_directive_prologue=%ld, catch_depth=%ld",
63848 (long) stmt_id, (long) temp_at_entry, (long) labels_len_at_entry,
63849 (long) comp_ctx->curr_func.is_strict, (long) comp_ctx->curr_func.in_directive_prologue,
63850 (long) comp_ctx->curr_func.catch_depth));
63851
63852 /* The directive prologue flag is cleared by default so that it is
63853 * unset for any recursive statement parsing. It is only "revived"
63854 * if a directive is detected. (We could also make directives only
63855 * allowed if 'allow_source_elem' was true.)
63856 */
63857 comp_ctx->curr_func.in_directive_prologue = 0;
63858
63859 retry_parse:
63860
63861 DUK_DDD(DUK_DDDPRINT("try stmt parse, stmt_id=%ld, label_id=%ld, allow_source_elem=%ld, catch_depth=%ld",
63862 (long) stmt_id, (long) label_id, (long) allow_source_elem,
63863 (long) comp_ctx->curr_func.catch_depth));
63864
63865 /*
63866 * Detect iteration statements; if encountered, establish an
63867 * empty label.
63868 */
63869
63870 tok = comp_ctx->curr_token.t;
63871 if (tok == DUK_TOK_FOR || tok == DUK_TOK_DO || tok == DUK_TOK_WHILE ||
63872 tok == DUK_TOK_SWITCH) {
63873 DUK_DDD(DUK_DDDPRINT("iteration/switch statement -> add empty label"));
63874
63875 label_id = duk__stmt_label_site(comp_ctx, label_id);
63876 duk__add_label(comp_ctx,
63877 DUK_HTHREAD_STRING_EMPTY_STRING(thr),
63878 pc_at_entry /*pc_label*/,
63879 label_id);
63880 }
63881
63882 /*
63883 * Main switch for statement / source element type.
63884 */
63885
63886 switch (comp_ctx->curr_token.t) {
63887 case DUK_TOK_FUNCTION: {
63888 /*
63889 * Function declaration, function expression, or (non-standard)
63890 * function statement.
63891 *
63892 * The E5 specification only allows function declarations at
63893 * the top level (in "source elements"). An ExpressionStatement
63894 * is explicitly not allowed to begin with a "function" keyword
63895 * (E5 Section 12.4). Hence any non-error semantics for such
63896 * non-top-level statements are non-standard. Duktape semantics
63897 * for function statements are modelled after V8, see
63898 * test-dev-func-decl-outside-top.js.
63899 */
63900
63901#if defined(DUK_USE_NONSTD_FUNC_STMT)
63902 /* Lenient: allow function declarations outside top level in
63903 * non-strict mode but reject them in strict mode.
63904 */
63905 if (allow_source_elem || !comp_ctx->curr_func.is_strict)
63906#else /* DUK_USE_NONSTD_FUNC_STMT */
63907 /* Strict: never allow function declarations outside top level. */
63908 if (allow_source_elem)
63909#endif /* DUK_USE_NONSTD_FUNC_STMT */
63910 {
63911 /* FunctionDeclaration: not strictly a statement but handled as such.
63912 *
63913 * O(depth^2) parse count for inner functions is handled by recording a
63914 * lexer offset on the first compilation pass, so that the function can
63915 * be efficiently skipped on the second pass. This is encapsulated into
63916 * duk__parse_func_like_fnum().
63917 */
63918
63919 duk_int_t fnum;
63920
63921 DUK_DDD(DUK_DDDPRINT("function declaration statement"));
63922
63923 duk__advance(comp_ctx); /* eat 'function' */
63924 fnum = duk__parse_func_like_fnum(comp_ctx, 1 /*is_decl*/, 0 /*is_setget*/);
63925
63926 if (comp_ctx->curr_func.in_scanning) {
63927 duk_uarridx_t n;
63928 duk_hstring *h_funcname;
63929
63930 duk_get_prop_index(ctx, comp_ctx->curr_func.funcs_idx, fnum * 3);
63931 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME); /* -> [ ... func name ] */
63932 h_funcname = duk_get_hstring(ctx, -1);
63933 DUK_ASSERT(h_funcname != NULL);
63934
63935 DUK_DDD(DUK_DDDPRINT("register function declaration %!O in pass 1, fnum %ld",
63936 (duk_heaphdr *) h_funcname, (long) fnum));
63937 n = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.decls_idx);
63938 duk_push_hstring(ctx, h_funcname);
63939 duk_put_prop_index(ctx, comp_ctx->curr_func.decls_idx, n);
63940 duk_push_int(ctx, (duk_int_t) (DUK_DECL_TYPE_FUNC + (fnum << 8)));
63941 duk_put_prop_index(ctx, comp_ctx->curr_func.decls_idx, n + 1);
63942
63943 duk_pop_n(ctx, 2);
63944 }
63945
63946 /* no statement value (unlike function expression) */
63947 stmt_flags = 0;
63948 break;
63949 } else {
11fdf7f2 63950 DUK_ERROR_SYNTAX(thr, DUK_STR_FUNC_STMT_NOT_ALLOWED);
7c673cae
FG
63951 }
63952 break;
63953 }
63954 case DUK_TOK_LCURLY: {
63955 DUK_DDD(DUK_DDDPRINT("block statement"));
63956 duk__advance(comp_ctx);
63957 duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
63958 /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
63959 if (label_id >= 0) {
63960 duk__patch_jump_here(comp_ctx, pc_at_entry + 1); /* break jump */
63961 }
63962 stmt_flags = 0;
63963 break;
63964 }
11fdf7f2
TL
63965 case DUK_TOK_CONST: {
63966 DUK_DDD(DUK_DDDPRINT("constant declaration statement"));
63967 duk__parse_var_stmt(comp_ctx, res, DUK__EXPR_FLAG_REQUIRE_INIT /*expr_flags*/);
63968 stmt_flags = DUK__HAS_TERM;
63969 break;
63970 }
7c673cae
FG
63971 case DUK_TOK_VAR: {
63972 DUK_DDD(DUK_DDDPRINT("variable declaration statement"));
11fdf7f2 63973 duk__parse_var_stmt(comp_ctx, res, 0 /*expr_flags*/);
7c673cae
FG
63974 stmt_flags = DUK__HAS_TERM;
63975 break;
63976 }
63977 case DUK_TOK_SEMICOLON: {
63978 /* empty statement with an explicit semicolon */
63979 DUK_DDD(DUK_DDDPRINT("empty statement"));
63980 stmt_flags = DUK__HAS_TERM;
63981 break;
63982 }
63983 case DUK_TOK_IF: {
63984 DUK_DDD(DUK_DDDPRINT("if statement"));
63985 duk__parse_if_stmt(comp_ctx, res);
63986 if (label_id >= 0) {
63987 duk__patch_jump_here(comp_ctx, pc_at_entry + 1); /* break jump */
63988 }
63989 stmt_flags = 0;
63990 break;
63991 }
63992 case DUK_TOK_DO: {
63993 /*
63994 * Do-while statement is mostly trivial, but there is special
63995 * handling for automatic semicolon handling (triggered by the
63996 * DUK__ALLOW_AUTO_SEMI_ALWAYS) flag related to a bug filed at:
63997 *
63998 * https://bugs.ecmascript.org/show_bug.cgi?id=8
63999 *
64000 * See doc/compiler.rst for details.
64001 */
64002 DUK_DDD(DUK_DDDPRINT("do statement"));
64003 DUK_ASSERT(label_id >= 0);
64004 duk__update_label_flags(comp_ctx,
64005 label_id,
64006 DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE);
64007 duk__parse_do_stmt(comp_ctx, res, pc_at_entry);
64008 stmt_flags = DUK__HAS_TERM | DUK__ALLOW_AUTO_SEMI_ALWAYS; /* DUK__ALLOW_AUTO_SEMI_ALWAYS workaround */
64009 break;
64010 }
64011 case DUK_TOK_WHILE: {
64012 DUK_DDD(DUK_DDDPRINT("while statement"));
64013 DUK_ASSERT(label_id >= 0);
64014 duk__update_label_flags(comp_ctx,
64015 label_id,
64016 DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE);
64017 duk__parse_while_stmt(comp_ctx, res, pc_at_entry);
64018 stmt_flags = 0;
64019 break;
64020 }
64021 case DUK_TOK_FOR: {
64022 /*
64023 * For/for-in statement is complicated to parse because
64024 * determining the statement type (three-part for vs. a
64025 * for-in) requires potential backtracking.
64026 *
64027 * See the helper for the messy stuff.
64028 */
64029 DUK_DDD(DUK_DDDPRINT("for/for-in statement"));
64030 DUK_ASSERT(label_id >= 0);
64031 duk__update_label_flags(comp_ctx,
64032 label_id,
64033 DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE);
64034 duk__parse_for_stmt(comp_ctx, res, pc_at_entry);
64035 stmt_flags = 0;
64036 break;
64037 }
64038 case DUK_TOK_CONTINUE:
64039 case DUK_TOK_BREAK: {
64040 DUK_DDD(DUK_DDDPRINT("break/continue statement"));
64041 duk__parse_break_or_continue_stmt(comp_ctx, res);
64042 stmt_flags = DUK__HAS_TERM | DUK__IS_TERMINAL;
64043 break;
64044 }
64045 case DUK_TOK_RETURN: {
64046 DUK_DDD(DUK_DDDPRINT("return statement"));
64047 duk__parse_return_stmt(comp_ctx, res);
64048 stmt_flags = DUK__HAS_TERM | DUK__IS_TERMINAL;
64049 break;
64050 }
64051 case DUK_TOK_WITH: {
64052 DUK_DDD(DUK_DDDPRINT("with statement"));
64053 comp_ctx->curr_func.with_depth++;
64054 duk__parse_with_stmt(comp_ctx, res);
64055 if (label_id >= 0) {
64056 duk__patch_jump_here(comp_ctx, pc_at_entry + 1); /* break jump */
64057 }
64058 comp_ctx->curr_func.with_depth--;
64059 stmt_flags = 0;
64060 break;
64061 }
64062 case DUK_TOK_SWITCH: {
64063 /*
64064 * The switch statement is pretty messy to compile.
64065 * See the helper for details.
64066 */
64067 DUK_DDD(DUK_DDDPRINT("switch statement"));
64068 DUK_ASSERT(label_id >= 0);
64069 duk__update_label_flags(comp_ctx,
64070 label_id,
64071 DUK_LABEL_FLAG_ALLOW_BREAK); /* don't allow continue */
64072 duk__parse_switch_stmt(comp_ctx, res, pc_at_entry);
64073 stmt_flags = 0;
64074 break;
64075 }
64076 case DUK_TOK_THROW: {
64077 DUK_DDD(DUK_DDDPRINT("throw statement"));
64078 duk__parse_throw_stmt(comp_ctx, res);
64079 stmt_flags = DUK__HAS_TERM | DUK__IS_TERMINAL;
64080 break;
64081 }
64082 case DUK_TOK_TRY: {
64083 DUK_DDD(DUK_DDDPRINT("try statement"));
64084 duk__parse_try_stmt(comp_ctx, res);
64085 stmt_flags = 0;
64086 break;
64087 }
64088 case DUK_TOK_DEBUGGER: {
11fdf7f2 64089 duk__advance(comp_ctx);
7c673cae
FG
64090#if defined(DUK_USE_DEBUGGER_SUPPORT)
64091 DUK_DDD(DUK_DDDPRINT("debugger statement: debugging enabled, emit debugger opcode"));
64092 duk__emit_extraop_only(comp_ctx, DUK_EXTRAOP_DEBUGGER);
64093#else
64094 DUK_DDD(DUK_DDDPRINT("debugger statement: ignored"));
64095#endif
7c673cae
FG
64096 stmt_flags = DUK__HAS_TERM;
64097 break;
64098 }
64099 default: {
64100 /*
64101 * Else, must be one of:
64102 * - ExpressionStatement, possibly a directive (String)
64103 * - LabelledStatement (Identifier followed by ':')
64104 *
64105 * Expressions beginning with 'function' keyword are covered by a case
64106 * above (such expressions are not allowed in standard E5 anyway).
64107 * Also expressions starting with '{' are interpreted as block
64108 * statements. See E5 Section 12.4.
64109 *
64110 * Directive detection is tricky; see E5 Section 14.1 on directive
64111 * prologue. A directive is an expression statement with a single
64112 * string literal and an explicit or automatic semicolon. Escape
64113 * characters are significant and no parens etc are allowed:
64114 *
64115 * 'use strict'; // valid 'use strict' directive
64116 * 'use\u0020strict'; // valid directive, not a 'use strict' directive
64117 * ('use strict'); // not a valid directive
64118 *
64119 * The expression is determined to consist of a single string literal
64120 * based on duk__expr_nud() and duk__expr_led() call counts. The string literal
64121 * of a 'use strict' directive is determined to lack any escapes based
64122 * num_escapes count from the lexer. Note that other directives may be
64123 * allowed to contain escapes, so a directive with escapes does not
64124 * terminate a directive prologue.
64125 *
64126 * We rely on the fact that the expression parser will not emit any
64127 * code for a single token expression. However, it will generate an
64128 * intermediate value which we will then successfully ignore.
64129 *
64130 * A similar approach is used for labels.
64131 */
64132
64133 duk_bool_t single_token;
64134
64135 DUK_DDD(DUK_DDDPRINT("expression statement"));
64136 duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
64137
64138 single_token = (comp_ctx->curr_func.nud_count == 1 && /* one token */
64139 comp_ctx->curr_func.led_count == 0); /* no operators */
64140
64141 if (single_token &&
64142 comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
64143 comp_ctx->curr_token.t == DUK_TOK_COLON) {
64144 /*
64145 * Detected label
64146 */
64147
64148 duk_hstring *h_lab;
64149
64150 /* expected ival */
64151 DUK_ASSERT(res->t == DUK_IVAL_VAR);
64152 DUK_ASSERT(res->x1.t == DUK_ISPEC_VALUE);
64153 DUK_ASSERT(DUK_TVAL_IS_STRING(duk_get_tval(ctx, res->x1.valstack_idx)));
64154 h_lab = comp_ctx->prev_token.str1;
64155 DUK_ASSERT(h_lab != NULL);
64156
64157 DUK_DDD(DUK_DDDPRINT("explicit label site for label '%!O'",
64158 (duk_heaphdr *) h_lab));
64159
64160 duk__advance(comp_ctx); /* eat colon */
64161
64162 label_id = duk__stmt_label_site(comp_ctx, label_id);
64163
64164 duk__add_label(comp_ctx,
64165 h_lab,
64166 pc_at_entry /*pc_label*/,
64167 label_id);
64168
64169 /* a statement following a label cannot be a source element
64170 * (a function declaration).
64171 */
64172 allow_source_elem = 0;
64173
64174 DUK_DDD(DUK_DDDPRINT("label handled, retry statement parsing"));
64175 goto retry_parse;
64176 }
64177
64178 stmt_flags = 0;
64179
64180 if (dir_prol_at_entry && /* still in prologue */
64181 single_token && /* single string token */
64182 comp_ctx->prev_token.t == DUK_TOK_STRING) {
64183 /*
64184 * Detected a directive
64185 */
64186 duk_hstring *h_dir;
64187
64188 /* expected ival */
64189 DUK_ASSERT(res->t == DUK_IVAL_PLAIN);
64190 DUK_ASSERT(res->x1.t == DUK_ISPEC_VALUE);
64191 DUK_ASSERT(DUK_TVAL_IS_STRING(duk_get_tval(ctx, res->x1.valstack_idx)));
64192 h_dir = comp_ctx->prev_token.str1;
64193 DUK_ASSERT(h_dir != NULL);
64194
64195 DUK_DDD(DUK_DDDPRINT("potential directive: %!O", h_dir));
64196
64197 stmt_flags |= DUK__STILL_PROLOGUE;
64198
64199 /* Note: escaped characters differentiate directives */
64200
64201 if (comp_ctx->prev_token.num_escapes > 0) {
64202 DUK_DDD(DUK_DDDPRINT("directive contains escapes: valid directive "
64203 "but we ignore such directives"));
64204 } else {
64205 /*
64206 * The length comparisons are present to handle
64207 * strings like "use strict\u0000foo" as required.
64208 */
64209
64210 if (DUK_HSTRING_GET_BYTELEN(h_dir) == 10 &&
64211 DUK_STRNCMP((const char *) DUK_HSTRING_GET_DATA(h_dir), "use strict", 10) == 0) {
64212#if defined(DUK_USE_STRICT_DECL)
64213 DUK_DDD(DUK_DDDPRINT("use strict directive detected: strict flag %ld -> %ld",
64214 (long) comp_ctx->curr_func.is_strict, (long) 1));
64215 comp_ctx->curr_func.is_strict = 1;
64216#else
64217 DUK_DDD(DUK_DDDPRINT("use strict detected but strict declarations disabled, ignoring"));
64218#endif
64219 } else if (DUK_HSTRING_GET_BYTELEN(h_dir) == 14 &&
64220 DUK_STRNCMP((const char *) DUK_HSTRING_GET_DATA(h_dir), "use duk notail", 14) == 0) {
64221 DUK_DDD(DUK_DDDPRINT("use duk notail directive detected: notail flag %ld -> %ld",
64222 (long) comp_ctx->curr_func.is_notail, (long) 1));
64223 comp_ctx->curr_func.is_notail = 1;
64224 } else {
64225 DUK_DD(DUK_DDPRINT("unknown directive: '%!O', ignoring but not terminating "
64226 "directive prologue", (duk_hobject *) h_dir));
64227 }
64228 }
64229 } else {
64230 DUK_DDD(DUK_DDDPRINT("non-directive expression statement or no longer in prologue; "
64231 "prologue terminated if still active"));
64232 }
64233
64234 stmt_flags |= DUK__HAS_VAL | DUK__HAS_TERM;
64235 }
64236 } /* end switch (tok) */
64237
64238 /*
64239 * Statement value handling.
64240 *
64241 * Global code and eval code has an implicit return value
64242 * which comes from the last statement with a value
64243 * (technically a non-"empty" continuation, which is
64244 * different from an empty statement).
64245 *
64246 * Since we don't know whether a later statement will
64247 * override the value of the current statement, we need
64248 * to coerce the statement value to a register allocated
64249 * for implicit return values. In other cases we need
64250 * to coerce the statement value to a plain value to get
64251 * any side effects out (consider e.g. "foo.bar;").
64252 */
64253
64254 /* XXX: what about statements which leave a half-cooked value in 'res'
64255 * but have no stmt value? Any such statements?
64256 */
64257
64258 if (stmt_flags & DUK__HAS_VAL) {
64259 duk_reg_t reg_stmt_value = comp_ctx->curr_func.reg_stmt_value;
64260 if (reg_stmt_value >= 0) {
64261 duk__ivalue_toforcedreg(comp_ctx, res, reg_stmt_value);
64262 } else {
64263 duk__ivalue_toplain_ignore(comp_ctx, res);
64264 }
64265 } else {
64266 ;
64267 }
64268
64269 /*
64270 * Statement terminator check, including automatic semicolon
64271 * handling. After this step, 'curr_tok' should be the first
64272 * token after a possible statement terminator.
64273 */
64274
64275 if (stmt_flags & DUK__HAS_TERM) {
64276 if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON) {
64277 DUK_DDD(DUK_DDDPRINT("explicit semicolon terminates statement"));
64278 duk__advance(comp_ctx);
64279 } else {
64280 if (comp_ctx->curr_token.allow_auto_semi) {
64281 DUK_DDD(DUK_DDDPRINT("automatic semicolon terminates statement"));
64282 } else if (stmt_flags & DUK__ALLOW_AUTO_SEMI_ALWAYS) {
64283 /* XXX: make this lenience dependent on flags or strictness? */
64284 DUK_DDD(DUK_DDDPRINT("automatic semicolon terminates statement (allowed for compatibility "
64285 "even though no lineterm present before next token)"));
64286 } else {
11fdf7f2 64287 DUK_ERROR_SYNTAX(thr, DUK_STR_UNTERMINATED_STMT);
7c673cae
FG
64288 }
64289 }
64290 } else {
64291 DUK_DDD(DUK_DDDPRINT("statement has no terminator"));
64292 }
64293
64294 /*
64295 * Directive prologue tracking.
64296 */
64297
64298 if (stmt_flags & DUK__STILL_PROLOGUE) {
64299 DUK_DDD(DUK_DDDPRINT("setting in_directive_prologue"));
64300 comp_ctx->curr_func.in_directive_prologue = 1;
64301 }
64302
64303 /*
64304 * Cleanups (all statement parsing flows through here).
64305 *
64306 * Pop label site and reset labels. Reset 'next temp' to value at
64307 * entry to reuse temps.
64308 */
64309
64310 if (label_id >= 0) {
64311 duk__emit_extraop_bc(comp_ctx,
64312 DUK_EXTRAOP_ENDLABEL,
64313 (duk_regconst_t) label_id);
64314 }
64315
64316 DUK__SETTEMP(comp_ctx, temp_at_entry);
64317
64318 duk__reset_labels_to_length(comp_ctx, labels_len_at_entry);
64319
64320 /* XXX: return indication of "terminalness" (e.g. a 'throw' is terminal) */
64321
64322 DUK__RECURSION_DECREASE(comp_ctx, thr);
64323}
64324
64325#undef DUK__HAS_VAL
64326#undef DUK__HAS_TERM
64327#undef DUK__ALLOW_AUTO_SEMI_ALWAYS
64328
64329/*
64330 * Parse a statement list.
64331 *
64332 * Handles automatic semicolon insertion and implicit return value.
64333 *
64334 * Upon entry, 'curr_tok' should contain the first token of the first
64335 * statement (parsed in the "allow regexp literal" mode). Upon exit,
64336 * 'curr_tok' contains the token following the statement list terminator
64337 * (EOF or closing brace).
64338 */
64339
64340DUK_LOCAL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_source_elem, duk_bool_t expect_eof) {
64341 duk_hthread *thr = comp_ctx->thr;
64342 duk_context *ctx = (duk_context *) thr;
64343 duk_ivalue res_alloc;
64344 duk_ivalue *res = &res_alloc;
64345
64346 /* Setup state. Initial ivalue is 'undefined'. */
64347
64348 duk_require_stack(ctx, DUK__PARSE_STATEMENTS_SLOTS);
64349
64350 /* XXX: 'res' setup can be moved to function body level; in fact, two 'res'
64351 * intermediate values suffice for parsing of each function. Nesting is needed
64352 * for nested functions (which may occur inside expressions).
64353 */
64354
64355 DUK_MEMZERO(&res_alloc, sizeof(res_alloc));
64356 res->t = DUK_IVAL_PLAIN;
64357 res->x1.t = DUK_ISPEC_VALUE;
64358 res->x1.valstack_idx = duk_get_top(ctx);
64359 res->x2.valstack_idx = res->x1.valstack_idx + 1;
64360 duk_push_undefined(ctx);
64361 duk_push_undefined(ctx);
64362
64363 /* Parse statements until a closing token (EOF or '}') is found. */
64364
64365 for (;;) {
64366 /* Check whether statement list ends. */
64367
64368 if (expect_eof) {
64369 if (comp_ctx->curr_token.t == DUK_TOK_EOF) {
64370 break;
64371 }
64372 } else {
64373 if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
64374 break;
64375 }
64376 }
64377
64378 /* Check statement type based on the first token type.
64379 *
64380 * Note: expression parsing helpers expect 'curr_tok' to
64381 * contain the first token of the expression upon entry.
64382 */
64383
64384 DUK_DDD(DUK_DDDPRINT("TOKEN %ld (non-whitespace, non-comment)", (long) comp_ctx->curr_token.t));
64385
64386 duk__parse_stmt(comp_ctx, res, allow_source_elem);
64387 }
64388
64389 duk__advance(comp_ctx);
64390
64391 /* Tear down state. */
64392
64393 duk_pop_2(ctx);
64394}
64395
64396/*
64397 * Declaration binding instantiation conceptually happens when calling a
64398 * function; for us it essentially means that function prologue. The
64399 * conceptual process is described in E5 Section 10.5.
64400 *
64401 * We need to keep track of all encountered identifiers to (1) create an
64402 * identifier-to-register map ("varmap"); and (2) detect duplicate
64403 * declarations. Identifiers which are not bound to registers still need
64404 * to be tracked for detecting duplicates. Currently such identifiers
64405 * are put into the varmap with a 'null' value, which is later cleaned up.
64406 *
64407 * To support functions with a large number of variable and function
64408 * declarations, registers are not allocated beyond a certain limit;
64409 * after that limit, variables and functions need slow path access.
64410 * Arguments are currently always register bound, which imposes a hard
64411 * (and relatively small) argument count limit.
64412 *
64413 * Some bindings in E5 are not configurable (= deletable) and almost all
64414 * are mutable (writable). Exceptions are:
64415 *
64416 * - The 'arguments' binding, established only if no shadowing argument
64417 * or function declaration exists. We handle 'arguments' creation
64418 * and binding through an explicit slow path environment record.
64419 *
64420 * - The "name" binding for a named function expression. This is also
64421 * handled through an explicit slow path environment record.
64422 */
64423
64424/* XXX: add support for variables to not be register bound always, to
64425 * handle cases with a very large number of variables?
64426 */
64427
64428DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ctx, duk_reg_t *out_stmt_value_reg) {
64429 duk_hthread *thr = comp_ctx->thr;
64430 duk_context *ctx = (duk_context *) thr;
64431 duk_hstring *h_name;
64432 duk_bool_t configurable_bindings;
64433 duk_uarridx_t num_args;
64434 duk_uarridx_t num_decls;
64435 duk_regconst_t rc_name;
64436 duk_small_uint_t declvar_flags;
64437 duk_uarridx_t i;
64438#ifdef DUK_USE_ASSERTIONS
64439 duk_idx_t entry_top;
64440#endif
64441
64442#ifdef DUK_USE_ASSERTIONS
64443 entry_top = duk_get_top(ctx);
64444#endif
64445
64446 /*
64447 * Preliminaries
64448 */
64449
64450 configurable_bindings = comp_ctx->curr_func.is_eval;
64451 DUK_DDD(DUK_DDDPRINT("configurable_bindings=%ld", (long) configurable_bindings));
64452
64453 /* varmap is already in comp_ctx->curr_func.varmap_idx */
64454
64455 /*
64456 * Function formal arguments, always bound to registers
64457 * (there's no support for shuffling them now).
64458 */
64459
64460 num_args = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.argnames_idx);
64461 DUK_DDD(DUK_DDDPRINT("num_args=%ld", (long) num_args));
64462 /* XXX: check num_args */
64463
64464 for (i = 0; i < num_args; i++) {
64465 duk_get_prop_index(ctx, comp_ctx->curr_func.argnames_idx, i);
64466 h_name = duk_get_hstring(ctx, -1);
64467 DUK_ASSERT(h_name != NULL);
64468
64469 if (comp_ctx->curr_func.is_strict) {
64470 if (duk__hstring_is_eval_or_arguments(comp_ctx, h_name)) {
64471 DUK_DDD(DUK_DDDPRINT("arg named 'eval' or 'arguments' in strict mode -> SyntaxError"));
64472 goto error_argname;
64473 }
64474 duk_dup_top(ctx);
64475 if (duk_has_prop(ctx, comp_ctx->curr_func.varmap_idx)) {
64476 DUK_DDD(DUK_DDDPRINT("duplicate arg name in strict mode -> SyntaxError"));
64477 goto error_argname;
64478 }
64479
64480 /* Ensure argument name is not a reserved word in current
64481 * (final) strictness. Formal argument parsing may not
64482 * catch reserved names if strictness changes during
64483 * parsing.
64484 *
64485 * We only need to do this in strict mode because non-strict
64486 * keyword are always detected in formal argument parsing.
64487 */
64488
64489 if (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(h_name)) {
64490 goto error_argname;
64491 }
64492 }
64493
64494 /* overwrite any previous binding of the same name; the effect is
64495 * that last argument of a certain name wins.
64496 */
64497
64498 /* only functions can have arguments */
64499 DUK_ASSERT(comp_ctx->curr_func.is_function);
64500 duk_push_uarridx(ctx, i); /* -> [ ... name index ] */
64501 duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx); /* -> [ ... ] */
64502
64503 /* no code needs to be emitted, the regs already have values */
64504 }
64505
64506 /* use temp_next for tracking register allocations */
64507 DUK__SETTEMP_CHECKMAX(comp_ctx, (duk_reg_t) num_args);
64508
64509 /*
64510 * After arguments, allocate special registers (like shuffling temps)
64511 */
64512
64513 if (out_stmt_value_reg) {
64514 *out_stmt_value_reg = DUK__ALLOCTEMP(comp_ctx);
64515 }
64516 if (comp_ctx->curr_func.needs_shuffle) {
64517 duk_reg_t shuffle_base = DUK__ALLOCTEMPS(comp_ctx, 3);
64518 comp_ctx->curr_func.shuffle1 = shuffle_base;
64519 comp_ctx->curr_func.shuffle2 = shuffle_base + 1;
64520 comp_ctx->curr_func.shuffle3 = shuffle_base + 2;
64521 DUK_D(DUK_DPRINT("shuffle registers needed by function, allocated: %ld %ld %ld",
64522 (long) comp_ctx->curr_func.shuffle1,
64523 (long) comp_ctx->curr_func.shuffle2,
64524 (long) comp_ctx->curr_func.shuffle3));
64525 }
64526 if (comp_ctx->curr_func.temp_next > 0x100) {
64527 DUK_D(DUK_DPRINT("not enough 8-bit regs: temp_next=%ld", (long) comp_ctx->curr_func.temp_next));
64528 goto error_outofregs;
64529 }
64530
64531 /*
64532 * Function declarations
64533 */
64534
64535 num_decls = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.decls_idx);
64536 DUK_DDD(DUK_DDDPRINT("num_decls=%ld -> %!T",
64537 (long) num_decls,
64538 (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.decls_idx)));
64539 for (i = 0; i < num_decls; i += 2) {
64540 duk_int_t decl_type;
64541 duk_int_t fnum;
64542
64543 duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i + 1); /* decl type */
64544 decl_type = duk_to_int(ctx, -1);
64545 fnum = decl_type >> 8; /* XXX: macros */
64546 decl_type = decl_type & 0xff;
64547 duk_pop(ctx);
64548
64549 if (decl_type != DUK_DECL_TYPE_FUNC) {
64550 continue;
64551 }
64552
64553 duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i); /* decl name */
64554
64555 /* XXX: spilling */
64556 if (comp_ctx->curr_func.is_function) {
64557 duk_reg_t reg_bind;
64558 duk_dup_top(ctx);
64559 if (duk_has_prop(ctx, comp_ctx->curr_func.varmap_idx)) {
64560 /* shadowed; update value */
64561 duk_dup_top(ctx);
64562 duk_get_prop(ctx, comp_ctx->curr_func.varmap_idx);
64563 reg_bind = duk_to_int(ctx, -1); /* [ ... name reg_bind ] */
64564 duk__emit_a_bc(comp_ctx,
64565 DUK_OP_CLOSURE,
64566 (duk_regconst_t) reg_bind,
64567 (duk_regconst_t) fnum);
64568 } else {
64569 /* function: always register bound */
64570 reg_bind = DUK__ALLOCTEMP(comp_ctx);
64571 duk__emit_a_bc(comp_ctx,
64572 DUK_OP_CLOSURE,
64573 (duk_regconst_t) reg_bind,
64574 (duk_regconst_t) fnum);
64575 duk_push_int(ctx, (duk_int_t) reg_bind);
64576 }
64577 } else {
64578 /* Function declaration for global/eval code is emitted even
64579 * for duplicates, because of E5 Section 10.5, step 5.e of
64580 * E5.1 (special behavior for variable bound to global object).
64581 *
64582 * DECLVAR will not re-declare a variable as such, but will
64583 * update the binding value.
64584 */
64585
64586 duk_reg_t reg_temp = DUK__ALLOCTEMP(comp_ctx);
64587 duk_dup_top(ctx);
64588 rc_name = duk__getconst(comp_ctx);
64589 duk_push_null(ctx);
64590
64591 duk__emit_a_bc(comp_ctx,
64592 DUK_OP_CLOSURE,
64593 (duk_regconst_t) reg_temp,
64594 (duk_regconst_t) fnum);
64595
64596 declvar_flags = DUK_PROPDESC_FLAG_WRITABLE |
64597 DUK_PROPDESC_FLAG_ENUMERABLE |
64598 DUK_BC_DECLVAR_FLAG_FUNC_DECL;
64599
64600 if (configurable_bindings) {
64601 declvar_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
64602 }
64603
64604 duk__emit_a_b_c(comp_ctx,
64605 DUK_OP_DECLVAR | DUK__EMIT_FLAG_NO_SHUFFLE_A,
64606 (duk_regconst_t) declvar_flags /*flags*/,
64607 rc_name /*name*/,
64608 (duk_regconst_t) reg_temp /*value*/);
64609
64610 DUK__SETTEMP(comp_ctx, reg_temp); /* forget temp */
64611 }
64612
64613 DUK_DDD(DUK_DDDPRINT("function declaration to varmap: %!T -> %!T",
64614 (duk_tval *) duk_get_tval(ctx, -2),
64615 (duk_tval *) duk_get_tval(ctx, -1)));
64616
64617 duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx); /* [ ... name reg/null ] -> [ ... ] */
64618 }
64619
64620 /*
64621 * 'arguments' binding is special; if a shadowing argument or
64622 * function declaration exists, an arguments object will
64623 * definitely not be needed, regardless of whether the identifier
64624 * 'arguments' is referenced inside the function body.
64625 */
64626
64627 if (duk_has_prop_stridx(ctx, comp_ctx->curr_func.varmap_idx, DUK_STRIDX_LC_ARGUMENTS)) {
64628 DUK_DDD(DUK_DDDPRINT("'arguments' is shadowed by argument or function declaration "
64629 "-> arguments object creation can be skipped"));
64630 comp_ctx->curr_func.is_arguments_shadowed = 1;
64631 }
64632
64633 /*
64634 * Variable declarations.
64635 *
64636 * Unlike function declarations, variable declaration values don't get
64637 * assigned on entry. If a binding of the same name already exists, just
64638 * ignore it silently.
64639 */
64640
64641 for (i = 0; i < num_decls; i += 2) {
64642 duk_int_t decl_type;
64643
64644 duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i + 1); /* decl type */
64645 decl_type = duk_to_int(ctx, -1);
64646 decl_type = decl_type & 0xff;
64647 duk_pop(ctx);
64648
64649 if (decl_type != DUK_DECL_TYPE_VAR) {
64650 continue;
64651 }
64652
64653 duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i); /* decl name */
64654
64655 if (duk_has_prop(ctx, comp_ctx->curr_func.varmap_idx)) {
64656 /* shadowed, ignore */
64657 } else {
64658 duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i); /* decl name */
64659 h_name = duk_get_hstring(ctx, -1);
64660 DUK_ASSERT(h_name != NULL);
64661
64662 if (h_name == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr) &&
64663 !comp_ctx->curr_func.is_arguments_shadowed) {
64664 /* E5 Section steps 7-8 */
64665 DUK_DDD(DUK_DDDPRINT("'arguments' not shadowed by a function declaration, "
64666 "but appears as a variable declaration -> treat as "
64667 "a no-op for variable declaration purposes"));
64668 duk_pop(ctx);
64669 continue;
64670 }
64671
64672 /* XXX: spilling */
64673 if (comp_ctx->curr_func.is_function) {
64674 duk_reg_t reg_bind = DUK__ALLOCTEMP(comp_ctx);
64675 /* no need to init reg, it will be undefined on entry */
64676 duk_push_int(ctx, (duk_int_t) reg_bind);
64677 } else {
64678 duk_dup_top(ctx);
64679 rc_name = duk__getconst(comp_ctx);
64680 duk_push_null(ctx);
64681
64682 declvar_flags = DUK_PROPDESC_FLAG_WRITABLE |
64683 DUK_PROPDESC_FLAG_ENUMERABLE |
64684 DUK_BC_DECLVAR_FLAG_UNDEF_VALUE;
64685 if (configurable_bindings) {
64686 declvar_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
64687 }
64688
64689 duk__emit_a_b_c(comp_ctx,
64690 DUK_OP_DECLVAR | DUK__EMIT_FLAG_NO_SHUFFLE_A,
64691 (duk_regconst_t) declvar_flags /*flags*/,
64692 rc_name /*name*/,
64693 (duk_regconst_t) 0 /*value*/);
64694 }
64695
64696 duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx); /* [ ... name reg/null ] -> [ ... ] */
64697 }
64698 }
64699
64700 /*
64701 * Wrap up
64702 */
64703
64704 DUK_DDD(DUK_DDDPRINT("varmap: %!T, is_arguments_shadowed=%ld",
64705 (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx),
64706 (long) comp_ctx->curr_func.is_arguments_shadowed));
64707
64708 DUK_ASSERT_TOP(ctx, entry_top);
64709 return;
64710
64711 error_outofregs:
11fdf7f2 64712 DUK_ERROR_RANGE(thr, DUK_STR_REG_LIMIT);
7c673cae
FG
64713 DUK_UNREACHABLE();
64714 return;
64715
64716 error_argname:
11fdf7f2 64717 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_ARG_NAME);
7c673cae
FG
64718 DUK_UNREACHABLE();
64719 return;
64720}
64721
64722/*
64723 * Parse a function-body-like expression (FunctionBody or Program
64724 * in E5 grammar) using a two-pass parse. The productions appear
64725 * in the following contexts:
64726 *
64727 * - function expression
64728 * - function statement
64729 * - function declaration
64730 * - getter in object literal
64731 * - setter in object literal
64732 * - global code
64733 * - eval code
64734 * - Function constructor body
64735 *
64736 * This function only parses the statement list of the body; the argument
64737 * list and possible function name must be initialized by the caller.
64738 * For instance, for Function constructor, the argument names are originally
64739 * on the value stack. The parsing of statements ends either at an EOF or
64740 * a closing brace; this is controlled by an input flag.
64741 *
64742 * Note that there are many differences affecting parsing and even code
64743 * generation:
64744 *
64745 * - Global and eval code have an implicit return value generated
64746 * by the last statement; function code does not
64747 *
64748 * - Global code, eval code, and Function constructor body end in
64749 * an EOF, other bodies in a closing brace ('}')
64750 *
64751 * Upon entry, 'curr_tok' is ignored and the function will pull in the
64752 * first token on its own. Upon exit, 'curr_tok' is the terminating
64753 * token (EOF or closing brace).
64754 */
64755
64756DUK_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) {
64757 duk_compiler_func *func;
64758 duk_hthread *thr;
64759 duk_context *ctx;
64760 duk_reg_t reg_stmt_value = -1;
64761 duk_lexer_point lex_pt;
64762 duk_reg_t temp_first;
64763 duk_small_int_t compile_round = 1;
64764
64765 DUK_ASSERT(comp_ctx != NULL);
64766
64767 thr = comp_ctx->thr;
64768 ctx = (duk_context *) thr;
64769 DUK_ASSERT(thr != NULL);
64770
64771 func = &comp_ctx->curr_func;
64772 DUK_ASSERT(func != NULL);
64773
64774 DUK__RECURSION_INCREASE(comp_ctx, thr);
64775
64776 duk_require_stack(ctx, DUK__FUNCTION_BODY_REQUIRE_SLOTS);
64777
64778 /*
64779 * Store lexer position for a later rewind
64780 */
64781
64782 DUK_LEXER_GETPOINT(&comp_ctx->lex, &lex_pt);
64783
64784 /*
64785 * Program code (global and eval code) has an implicit return value
64786 * from the last statement value (e.g. eval("1; 2+3;") returns 3).
64787 * This is not the case with functions. If implicit statement return
64788 * value is requested, all statements are coerced to a register
64789 * allocated here, and used in the implicit return statement below.
64790 */
64791
64792 /* XXX: this is pointless here because pass 1 is throw-away */
64793 if (implicit_return_value) {
64794 reg_stmt_value = DUK__ALLOCTEMP(comp_ctx);
64795
64796 /* If an implicit return value is needed by caller, it must be
64797 * initialized to 'undefined' because we don't know whether any
64798 * non-empty (where "empty" is a continuation type, and different
64799 * from an empty statement) statements will be executed.
64800 *
64801 * However, since 1st pass is a throwaway one, no need to emit
64802 * it here.
64803 */
64804#if 0
64805 duk__emit_extraop_bc(comp_ctx,
64806 DUK_EXTRAOP_LDUNDEF,
64807 0);
64808#endif
64809 }
64810
64811 /*
64812 * First pass.
64813 *
64814 * Gather variable/function declarations needed for second pass.
64815 * Code generated is dummy and discarded.
64816 */
64817
64818 func->in_directive_prologue = 1;
64819 func->in_scanning = 1;
64820 func->may_direct_eval = 0;
64821 func->id_access_arguments = 0;
64822 func->id_access_slow = 0;
64823 func->reg_stmt_value = reg_stmt_value;
64824#if defined(DUK_USE_DEBUGGER_SUPPORT)
64825 func->min_line = DUK_INT_MAX;
64826 func->max_line = 0;
64827#endif
64828
64829 /* duk__parse_stmts() expects curr_tok to be set; parse in "allow regexp literal" mode with current strictness */
64830 if (expect_token >= 0) {
64831 /* Eating a left curly; regexp mode is allowed by left curly
64832 * based on duk__token_lbp[] automatically.
64833 */
64834 DUK_ASSERT(expect_token == DUK_TOK_LCURLY);
64835 duk__update_lineinfo_currtoken(comp_ctx);
64836 duk__advance_expect(comp_ctx, expect_token);
64837 } else {
64838 /* Need to set curr_token.t because lexing regexp mode depends on current
64839 * token type. Zero value causes "allow regexp" mode.
64840 */
64841 comp_ctx->curr_token.t = 0;
64842 duk__advance(comp_ctx);
64843 }
64844
64845 DUK_DDD(DUK_DDDPRINT("begin 1st pass"));
64846 duk__parse_stmts(comp_ctx,
64847 1, /* allow source elements */
64848 expect_eof); /* expect EOF instead of } */
64849 DUK_DDD(DUK_DDDPRINT("end 1st pass"));
64850
64851 /*
64852 * Second (and possibly third) pass.
64853 *
64854 * Generate actual code. In most cases the need for shuffle
64855 * registers is detected during pass 1, but in some corner cases
64856 * we'll only detect it during pass 2 and a third pass is then
64857 * needed (see GH-115).
64858 */
64859
64860 for (;;) {
64861 duk_bool_t needs_shuffle_before = comp_ctx->curr_func.needs_shuffle;
64862 compile_round++;
64863
64864 /*
64865 * Rewind lexer.
64866 *
64867 * duk__parse_stmts() expects curr_tok to be set; parse in "allow regexp
64868 * literal" mode with current strictness.
64869 *
64870 * curr_token line number info should be initialized for pass 2 before
64871 * generating prologue, to ensure prologue bytecode gets nice line numbers.
64872 */
64873
64874 DUK_DDD(DUK_DDDPRINT("rewind lexer"));
64875 DUK_LEXER_SETPOINT(&comp_ctx->lex, &lex_pt);
64876 comp_ctx->curr_token.t = 0; /* this is needed for regexp mode */
64877 comp_ctx->curr_token.start_line = 0; /* needed for line number tracking (becomes prev_token.start_line) */
64878 duk__advance(comp_ctx);
64879
64880 /*
64881 * Reset function state and perform register allocation, which creates
64882 * 'varmap' for second pass. Function prologue for variable declarations,
64883 * binding value initializations etc is emitted as a by-product.
64884 *
64885 * Strict mode restrictions for duplicate and invalid argument
64886 * names are checked here now that we know whether the function
64887 * is actually strict. See: test-dev-strict-mode-boundary.js.
64888 *
64889 * Inner functions are compiled during pass 1 and are not reset.
64890 */
64891
64892 duk__reset_func_for_pass2(comp_ctx);
64893 func->in_directive_prologue = 1;
64894 func->in_scanning = 0;
64895
64896 /* must be able to emit code, alloc consts, etc. */
64897
64898 duk__init_varmap_and_prologue_for_pass2(comp_ctx,
64899 (implicit_return_value ? &reg_stmt_value : NULL));
64900 func->reg_stmt_value = reg_stmt_value;
64901
64902 temp_first = DUK__GETTEMP(comp_ctx);
64903
64904 func->temp_first = temp_first;
64905 func->temp_next = temp_first;
64906 func->stmt_next = 0;
64907 func->label_next = 0;
64908
64909 /* XXX: init or assert catch depth etc -- all values */
64910 func->id_access_arguments = 0;
64911 func->id_access_slow = 0;
64912
64913 /*
64914 * Check function name validity now that we know strictness.
64915 * This only applies to function declarations and expressions,
64916 * not setter/getter name.
64917 *
64918 * See: test-dev-strict-mode-boundary.js
64919 */
64920
64921 if (func->is_function && !func->is_setget && func->h_name != NULL) {
64922 if (func->is_strict) {
64923 if (duk__hstring_is_eval_or_arguments(comp_ctx, func->h_name)) {
64924 DUK_DDD(DUK_DDDPRINT("func name is 'eval' or 'arguments' in strict mode"));
64925 goto error_funcname;
64926 }
64927 if (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(func->h_name)) {
64928 DUK_DDD(DUK_DDDPRINT("func name is a reserved word in strict mode"));
64929 goto error_funcname;
64930 }
64931 } else {
64932 if (DUK_HSTRING_HAS_RESERVED_WORD(func->h_name) &&
64933 !DUK_HSTRING_HAS_STRICT_RESERVED_WORD(func->h_name)) {
64934 DUK_DDD(DUK_DDDPRINT("func name is a reserved word in non-strict mode"));
64935 goto error_funcname;
64936 }
64937 }
64938 }
64939
64940 /*
64941 * Second pass parsing.
64942 */
64943
64944 if (implicit_return_value) {
64945 /* Default implicit return value. */
64946 duk__emit_extraop_bc(comp_ctx,
64947 DUK_EXTRAOP_LDUNDEF,
64948 0);
64949 }
64950
64951 DUK_DDD(DUK_DDDPRINT("begin 2nd pass"));
64952 duk__parse_stmts(comp_ctx,
64953 1, /* allow source elements */
64954 expect_eof); /* expect EOF instead of } */
64955 DUK_DDD(DUK_DDDPRINT("end 2nd pass"));
64956
64957 duk__update_lineinfo_currtoken(comp_ctx);
64958
64959 if (needs_shuffle_before == comp_ctx->curr_func.needs_shuffle) {
64960 /* Shuffle decision not changed. */
64961 break;
64962 }
64963 if (compile_round >= 3) {
64964 /* Should never happen but avoid infinite loop just in case. */
64965 DUK_D(DUK_DPRINT("more than 3 compile passes needed, should never happen"));
11fdf7f2 64966 DUK_ERROR_INTERNAL_DEFMSG(thr);
7c673cae
FG
64967 }
64968 DUK_D(DUK_DPRINT("need additional round to compile function, round now %d", (int) compile_round));
64969 }
64970
64971 /*
64972 * Emit a final RETURN.
64973 *
64974 * It would be nice to avoid emitting an unnecessary "return" opcode
64975 * if the current PC is not reachable. However, this cannot be reliably
64976 * detected; even if the previous instruction is an unconditional jump,
64977 * there may be a previous jump which jumps to current PC (which is the
64978 * case for iteration and conditional statements, for instance).
64979 */
64980
64981 /* XXX: request a "last statement is terminal" from duk__parse_stmt() and duk__parse_stmts();
64982 * we could avoid the last RETURN if we could ensure there is no way to get here
64983 * (directly or via a jump)
64984 */
64985
11fdf7f2 64986 DUK_ASSERT(comp_ctx->curr_func.catch_depth == 0);
7c673cae
FG
64987 if (reg_stmt_value >= 0) {
64988 duk__emit_a_b(comp_ctx,
64989 DUK_OP_RETURN | DUK__EMIT_FLAG_NO_SHUFFLE_A,
11fdf7f2 64990 (duk_regconst_t) DUK_BC_RETURN_FLAG_HAVE_RETVAL /*flags*/,
7c673cae
FG
64991 (duk_regconst_t) reg_stmt_value /*reg*/);
64992 } else {
64993 duk__emit_a_b(comp_ctx,
64994 DUK_OP_RETURN | DUK__EMIT_FLAG_NO_SHUFFLE_A,
11fdf7f2 64995 (duk_regconst_t) 0 /*flags*/,
7c673cae
FG
64996 (duk_regconst_t) 0 /*reg(ignored)*/);
64997 }
64998
64999 /*
65000 * Peephole optimize JUMP chains.
65001 */
65002
65003 duk__peephole_optimize_bytecode(comp_ctx);
65004
65005 /*
65006 * comp_ctx->curr_func is now ready to be converted into an actual
65007 * function template.
65008 */
65009
65010 DUK__RECURSION_DECREASE(comp_ctx, thr);
65011 return;
65012
65013 error_funcname:
11fdf7f2 65014 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_FUNC_NAME);
7c673cae
FG
65015}
65016
65017/*
65018 * Parse a function-like expression:
65019 *
65020 * - function expression
65021 * - function declaration
65022 * - function statement (non-standard)
65023 * - setter/getter
65024 *
65025 * Adds the function to comp_ctx->curr_func function table and returns the
65026 * function number.
65027 *
65028 * On entry, curr_token points to:
65029 *
65030 * - the token after 'function' for function expression/declaration/statement
65031 * - the token after 'set' or 'get' for setter/getter
65032 */
65033
65034/* Parse formals. */
65035DUK_LOCAL void duk__parse_func_formals(duk_compiler_ctx *comp_ctx) {
65036 duk_hthread *thr = comp_ctx->thr;
65037 duk_context *ctx = (duk_context *) thr;
65038 duk_bool_t first = 1;
65039 duk_uarridx_t n;
65040
65041 for (;;) {
65042 if (comp_ctx->curr_token.t == DUK_TOK_RPAREN) {
65043 break;
65044 }
65045
65046 if (first) {
65047 /* no comma */
65048 first = 0;
65049 } else {
65050 duk__advance_expect(comp_ctx, DUK_TOK_COMMA);
65051 }
65052
65053 /* Note: when parsing a formal list in non-strict context, e.g.
65054 * "implements" is parsed as an identifier. When the function is
65055 * later detected to be strict, the argument list must be rechecked
65056 * against a larger set of reserved words (that of strict mode).
65057 * This is handled by duk__parse_func_body(). Here we recognize
65058 * whatever tokens are considered reserved in current strictness
65059 * (which is not always enough).
65060 */
65061
65062 if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) {
11fdf7f2 65063 DUK_ERROR_SYNTAX(thr, "expected identifier");
7c673cae
FG
65064 }
65065 DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_IDENTIFIER);
65066 DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
65067 DUK_DDD(DUK_DDDPRINT("formal argument: %!O",
65068 (duk_heaphdr *) comp_ctx->curr_token.str1));
65069
65070 /* XXX: append primitive */
65071 duk_push_hstring(ctx, comp_ctx->curr_token.str1);
65072 n = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.argnames_idx);
65073 duk_put_prop_index(ctx, comp_ctx->curr_func.argnames_idx, n);
65074
65075 duk__advance(comp_ctx); /* eat identifier */
65076 }
65077}
65078
65079/* Parse a function-like expression, assuming that 'comp_ctx->curr_func' is
65080 * correctly set up. Assumes that curr_token is just after 'function' (or
65081 * 'set'/'get' etc).
65082 */
65083DUK_LOCAL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_bool_t is_decl, duk_bool_t is_setget) {
65084 duk_hthread *thr = comp_ctx->thr;
65085 duk_context *ctx = (duk_context *) thr;
65086
65087 DUK_ASSERT(comp_ctx->curr_func.num_formals == 0);
65088 DUK_ASSERT(comp_ctx->curr_func.is_function == 1);
65089 DUK_ASSERT(comp_ctx->curr_func.is_eval == 0);
65090 DUK_ASSERT(comp_ctx->curr_func.is_global == 0);
65091 DUK_ASSERT(comp_ctx->curr_func.is_setget == is_setget);
65092 DUK_ASSERT(comp_ctx->curr_func.is_decl == is_decl);
65093
65094 duk__update_lineinfo_currtoken(comp_ctx);
65095
65096 /*
65097 * Function name (if any)
65098 *
65099 * We don't check for prohibited names here, because we don't
65100 * yet know whether the function will be strict. Function body
65101 * parsing handles this retroactively.
65102 *
65103 * For function expressions and declarations function name must
65104 * be an Identifer (excludes reserved words). For setter/getter
65105 * it is a PropertyName which allows reserved words and also
65106 * strings and numbers (e.g. "{ get 1() { ... } }").
65107 */
65108
65109 if (is_setget) {
65110 /* PropertyName -> IdentifierName | StringLiteral | NumericLiteral */
65111 if (comp_ctx->curr_token.t_nores == DUK_TOK_IDENTIFIER ||
65112 comp_ctx->curr_token.t == DUK_TOK_STRING) {
65113 duk_push_hstring(ctx, comp_ctx->curr_token.str1); /* keep in valstack */
65114 } else if (comp_ctx->curr_token.t == DUK_TOK_NUMBER) {
65115 duk_push_number(ctx, comp_ctx->curr_token.num);
65116 duk_to_string(ctx, -1);
65117 } else {
11fdf7f2 65118 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_GETSET_NAME);
7c673cae
FG
65119 }
65120 comp_ctx->curr_func.h_name = duk_get_hstring(ctx, -1); /* borrowed reference */
65121 DUK_ASSERT(comp_ctx->curr_func.h_name != NULL);
65122 duk__advance(comp_ctx);
65123 } else {
65124 /* Function name is an Identifier (not IdentifierName), but we get
65125 * the raw name (not recognizing keywords) here and perform the name
65126 * checks only after pass 1.
65127 */
65128 if (comp_ctx->curr_token.t_nores == DUK_TOK_IDENTIFIER) {
65129 duk_push_hstring(ctx, comp_ctx->curr_token.str1); /* keep in valstack */
65130 comp_ctx->curr_func.h_name = duk_get_hstring(ctx, -1); /* borrowed reference */
65131 DUK_ASSERT(comp_ctx->curr_func.h_name != NULL);
65132 duk__advance(comp_ctx);
65133 } else {
65134 /* valstack will be unbalanced, which is OK */
65135 DUK_ASSERT(!is_setget);
65136 if (is_decl) {
11fdf7f2 65137 DUK_ERROR_SYNTAX(thr, DUK_STR_FUNC_NAME_REQUIRED);
7c673cae
FG
65138 }
65139 }
65140 }
65141
65142 DUK_DDD(DUK_DDDPRINT("function name: %!O",
65143 (duk_heaphdr *) comp_ctx->curr_func.h_name));
65144
65145 /*
65146 * Formal argument list
65147 *
65148 * We don't check for prohibited names or for duplicate argument
65149 * names here, becase we don't yet know whether the function will
65150 * be strict. Function body parsing handles this retroactively.
65151 */
65152
65153 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
65154
65155 duk__parse_func_formals(comp_ctx);
65156
65157 DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RPAREN);
65158 duk__advance(comp_ctx);
65159
65160 /*
65161 * Parse function body
65162 */
65163
65164 duk__parse_func_body(comp_ctx,
65165 0, /* expect_eof */
65166 0, /* implicit_return_value */
65167 DUK_TOK_LCURLY); /* expect_token */
65168
65169 /*
65170 * Convert duk_compiler_func to a function template and add it
65171 * to the parent function table.
65172 */
65173
65174 duk__convert_to_func_template(comp_ctx, is_setget /*force_no_namebind*/); /* -> [ ... func ] */
65175}
65176
65177/* Parse an inner function, adding the function template to the current function's
65178 * function table. Return a function number to be used by the outer function.
65179 *
65180 * Avoiding O(depth^2) inner function parsing is handled here. On the first pass,
65181 * compile and register the function normally into the 'funcs' array, also recording
65182 * a lexer point (offset/line) to the closing brace of the function. On the second
65183 * pass, skip the function and return the same 'fnum' as on the first pass by using
65184 * a running counter.
65185 *
65186 * An unfortunate side effect of this is that when parsing the inner function, almost
65187 * nothing is known of the outer function, i.e. the inner function's scope. We don't
65188 * need that information at the moment, but it would allow some optimizations if it
65189 * were used.
65190 */
65191DUK_LOCAL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_bool_t is_decl, duk_bool_t is_setget) {
65192 duk_hthread *thr = comp_ctx->thr;
65193 duk_context *ctx = (duk_context *) thr;
65194 duk_compiler_func old_func;
65195 duk_idx_t entry_top;
65196 duk_int_t fnum;
65197
65198 /*
65199 * On second pass, skip the function.
65200 */
65201
65202 if (!comp_ctx->curr_func.in_scanning) {
65203 duk_lexer_point lex_pt;
65204
65205 fnum = comp_ctx->curr_func.fnum_next++;
65206 duk_get_prop_index(ctx, comp_ctx->curr_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 1));
65207 lex_pt.offset = duk_to_int(ctx, -1);
65208 duk_pop(ctx);
65209 duk_get_prop_index(ctx, comp_ctx->curr_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 2));
65210 lex_pt.line = duk_to_int(ctx, -1);
65211 duk_pop(ctx);
65212
65213 DUK_DDD(DUK_DDDPRINT("second pass of an inner func, skip the function, reparse closing brace; lex offset=%ld, line=%ld",
65214 (long) lex_pt.offset, (long) lex_pt.line));
65215
65216 DUK_LEXER_SETPOINT(&comp_ctx->lex, &lex_pt);
65217 comp_ctx->curr_token.t = 0; /* this is needed for regexp mode */
65218 comp_ctx->curr_token.start_line = 0; /* needed for line number tracking (becomes prev_token.start_line) */
65219 duk__advance(comp_ctx);
65220 duk__advance_expect(comp_ctx, DUK_TOK_RCURLY);
65221
65222 return fnum;
65223 }
65224
65225 /*
65226 * On first pass, perform actual parsing. Remember valstack top on entry
65227 * to restore it later, and switch to using a new function in comp_ctx.
65228 */
65229
65230 entry_top = duk_get_top(ctx);
65231 DUK_DDD(DUK_DDDPRINT("before func: entry_top=%ld, curr_tok.start_offset=%ld",
65232 (long) entry_top, (long) comp_ctx->curr_token.start_offset));
65233
65234 DUK_MEMCPY(&old_func, &comp_ctx->curr_func, sizeof(duk_compiler_func));
65235
65236 DUK_MEMZERO(&comp_ctx->curr_func, sizeof(duk_compiler_func));
65237 duk__init_func_valstack_slots(comp_ctx);
65238 DUK_ASSERT(comp_ctx->curr_func.num_formals == 0);
65239
65240 /* inherit initial strictness from parent */
65241 comp_ctx->curr_func.is_strict = old_func.is_strict;
65242
65243 DUK_ASSERT(comp_ctx->curr_func.is_notail == 0);
65244 comp_ctx->curr_func.is_function = 1;
65245 DUK_ASSERT(comp_ctx->curr_func.is_eval == 0);
65246 DUK_ASSERT(comp_ctx->curr_func.is_global == 0);
65247 comp_ctx->curr_func.is_setget = is_setget;
65248 comp_ctx->curr_func.is_decl = is_decl;
65249
65250 /*
65251 * Parse inner function
65252 */
65253
65254 duk__parse_func_like_raw(comp_ctx, is_decl, is_setget); /* pushes function template */
65255
65256 /* prev_token.start_offset points to the closing brace here; when skipping
65257 * we're going to reparse the closing brace to ensure semicolon insertion
65258 * etc work as expected.
65259 */
65260 DUK_DDD(DUK_DDDPRINT("after func: prev_tok.start_offset=%ld, curr_tok.start_offset=%ld",
65261 (long) comp_ctx->prev_token.start_offset, (long) comp_ctx->curr_token.start_offset));
65262 DUK_ASSERT(comp_ctx->lex.input[comp_ctx->prev_token.start_offset] == (duk_uint8_t) DUK_ASC_RCURLY);
65263
65264 /* XXX: append primitive */
65265 DUK_ASSERT(duk_get_length(ctx, old_func.funcs_idx) == (duk_size_t) (old_func.fnum_next * 3));
65266 fnum = old_func.fnum_next++;
65267
65268 if (fnum > DUK__MAX_FUNCS) {
11fdf7f2 65269 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_FUNC_LIMIT);
7c673cae
FG
65270 }
65271
65272 /* array writes autoincrement length */
65273 (void) duk_put_prop_index(ctx, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3));
65274 duk_push_size_t(ctx, comp_ctx->prev_token.start_offset);
65275 (void) duk_put_prop_index(ctx, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 1));
65276 duk_push_int(ctx, comp_ctx->prev_token.start_line);
65277 (void) duk_put_prop_index(ctx, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 2));
65278
65279 /*
65280 * Cleanup: restore original function, restore valstack state.
65281 */
65282
65283 DUK_MEMCPY((void *) &comp_ctx->curr_func, (void *) &old_func, sizeof(duk_compiler_func));
65284 duk_set_top(ctx, entry_top);
65285
65286 DUK_ASSERT_TOP(ctx, entry_top);
65287
65288 return fnum;
65289}
65290
65291/*
65292 * Compile input string into an executable function template without
65293 * arguments.
65294 *
65295 * The string is parsed as the "Program" production of Ecmascript E5.
65296 * Compilation context can be either global code or eval code (see E5
65297 * Sections 14 and 15.1.2.1).
65298 *
65299 * Input stack: [ ... filename ]
65300 * Output stack: [ ... func_template ]
65301 */
65302
65303/* XXX: source code property */
65304
65305DUK_LOCAL duk_ret_t duk__js_compile_raw(duk_context *ctx) {
65306 duk_hthread *thr = (duk_hthread *) ctx;
65307 duk_hstring *h_filename;
65308 duk__compiler_stkstate *comp_stk;
65309 duk_compiler_ctx *comp_ctx;
65310 duk_lexer_point *lex_pt;
65311 duk_compiler_func *func;
65312 duk_idx_t entry_top;
65313 duk_bool_t is_strict;
65314 duk_bool_t is_eval;
65315 duk_bool_t is_funcexpr;
65316 duk_small_uint_t flags;
65317
65318 DUK_ASSERT(thr != NULL);
65319
65320 /*
65321 * Arguments check
65322 */
65323
65324 entry_top = duk_get_top(ctx);
65325 DUK_ASSERT(entry_top >= 2);
65326
65327 comp_stk = (duk__compiler_stkstate *) duk_require_pointer(ctx, -1);
65328 comp_ctx = &comp_stk->comp_ctx_alloc;
65329 lex_pt = &comp_stk->lex_pt_alloc;
65330 DUK_ASSERT(comp_ctx != NULL);
65331 DUK_ASSERT(lex_pt != NULL);
65332
65333 flags = comp_stk->flags;
65334 is_eval = (flags & DUK_JS_COMPILE_FLAG_EVAL ? 1 : 0);
65335 is_strict = (flags & DUK_JS_COMPILE_FLAG_STRICT ? 1 : 0);
65336 is_funcexpr = (flags & DUK_JS_COMPILE_FLAG_FUNCEXPR ? 1 : 0);
65337
65338 h_filename = duk_get_hstring(ctx, -2); /* may be undefined */
65339
65340 /*
65341 * Init compiler and lexer contexts
65342 */
65343
65344 func = &comp_ctx->curr_func;
65345#ifdef DUK_USE_EXPLICIT_NULL_INIT
65346 comp_ctx->thr = NULL;
65347 comp_ctx->h_filename = NULL;
65348 comp_ctx->prev_token.str1 = NULL;
65349 comp_ctx->prev_token.str2 = NULL;
65350 comp_ctx->curr_token.str1 = NULL;
65351 comp_ctx->curr_token.str2 = NULL;
65352#endif
65353
65354 duk_require_stack(ctx, DUK__COMPILE_ENTRY_SLOTS);
65355
65356 duk_push_dynamic_buffer(ctx, 0); /* entry_top + 0 */
65357 duk_push_undefined(ctx); /* entry_top + 1 */
65358 duk_push_undefined(ctx); /* entry_top + 2 */
65359 duk_push_undefined(ctx); /* entry_top + 3 */
65360 duk_push_undefined(ctx); /* entry_top + 4 */
65361
65362 comp_ctx->thr = thr;
65363 comp_ctx->h_filename = h_filename;
65364 comp_ctx->tok11_idx = entry_top + 1;
65365 comp_ctx->tok12_idx = entry_top + 2;
65366 comp_ctx->tok21_idx = entry_top + 3;
65367 comp_ctx->tok22_idx = entry_top + 4;
65368 comp_ctx->recursion_limit = DUK_USE_COMPILER_RECLIMIT;
65369
65370 /* comp_ctx->lex has been pre-initialized by caller: it has been
65371 * zeroed and input/input_length has been set.
65372 */
65373 comp_ctx->lex.thr = thr;
65374 /* comp_ctx->lex.input and comp_ctx->lex.input_length filled by caller */
65375 comp_ctx->lex.slot1_idx = comp_ctx->tok11_idx;
65376 comp_ctx->lex.slot2_idx = comp_ctx->tok12_idx;
65377 comp_ctx->lex.buf_idx = entry_top + 0;
65378 comp_ctx->lex.buf = (duk_hbuffer_dynamic *) duk_get_hbuffer(ctx, entry_top + 0);
65379 DUK_ASSERT(comp_ctx->lex.buf != NULL);
65380 DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(comp_ctx->lex.buf) && !DUK_HBUFFER_HAS_EXTERNAL(comp_ctx->lex.buf));
65381 comp_ctx->lex.token_limit = DUK_COMPILER_TOKEN_LIMIT;
65382
65383 lex_pt->offset = 0;
65384 lex_pt->line = 1;
65385 DUK_LEXER_SETPOINT(&comp_ctx->lex, lex_pt); /* fills window */
65386 comp_ctx->curr_token.start_line = 0; /* needed for line number tracking (becomes prev_token.start_line) */
65387
65388 /*
65389 * Initialize function state for a zero-argument function
65390 */
65391
65392 duk__init_func_valstack_slots(comp_ctx);
65393 DUK_ASSERT(func->num_formals == 0);
65394
65395 if (is_funcexpr) {
65396 /* Name will be filled from function expression, not by caller.
65397 * This case is used by Function constructor and duk_compile()
65398 * API with the DUK_COMPILE_FUNCTION option.
65399 */
65400 DUK_ASSERT(func->h_name == NULL);
65401 } else {
65402 duk_push_hstring_stridx(ctx, (is_eval ? DUK_STRIDX_EVAL :
65403 DUK_STRIDX_GLOBAL));
65404 func->h_name = duk_get_hstring(ctx, -1);
65405 }
65406
65407 /*
65408 * Parse a function body or a function-like expression, depending
65409 * on flags.
65410 */
65411
65412 func->is_strict = is_strict;
65413 func->is_setget = 0;
65414 func->is_decl = 0;
65415
65416 if (is_funcexpr) {
65417 func->is_function = 1;
65418 func->is_eval = 0;
65419 func->is_global = 0;
65420
65421 duk__advance(comp_ctx); /* init 'curr_token' */
65422 duk__advance_expect(comp_ctx, DUK_TOK_FUNCTION);
65423 (void) duk__parse_func_like_raw(comp_ctx,
65424 0, /* is_decl */
65425 0); /* is_setget */
65426 } else {
65427 func->is_function = 0;
65428 func->is_eval = is_eval;
65429 func->is_global = !is_eval;
65430
65431 duk__parse_func_body(comp_ctx,
65432 1, /* expect_eof */
65433 1, /* implicit_return_value */
65434 -1); /* expect_token */
65435 }
65436
65437 /*
65438 * Convert duk_compiler_func to a function template
65439 */
65440
65441 duk__convert_to_func_template(comp_ctx, 0 /*force_no_namebind*/);
65442
65443 /*
65444 * Wrapping duk_safe_call() will mangle the stack, just return stack top
65445 */
65446
65447 /* [ ... filename (temps) func ] */
65448
65449 return 1;
65450}
65451
65452DUK_INTERNAL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer, duk_size_t src_length, duk_small_uint_t flags) {
65453 duk_context *ctx = (duk_context *) thr;
65454 duk__compiler_stkstate comp_stk;
65455 duk_compiler_ctx *prev_ctx;
65456 duk_ret_t safe_rc;
65457
65458 /* XXX: this illustrates that a C catchpoint implemented using duk_safe_call()
65459 * is a bit heavy at the moment. The wrapper compiles to ~180 bytes on x64.
65460 * Alternatives would be nice.
65461 */
65462
65463 DUK_ASSERT(thr != NULL);
65464 DUK_ASSERT(src_buffer != NULL);
65465
65466 /* preinitialize lexer state partially */
65467 DUK_MEMZERO(&comp_stk, sizeof(comp_stk));
65468 comp_stk.flags = flags;
65469 DUK_LEXER_INITCTX(&comp_stk.comp_ctx_alloc.lex);
65470 comp_stk.comp_ctx_alloc.lex.input = src_buffer;
65471 comp_stk.comp_ctx_alloc.lex.input_length = src_length;
65472
65473 duk_push_pointer(ctx, (void *) &comp_stk);
65474
65475 /* [ ... filename &comp_stk ] */
65476
65477 prev_ctx = thr->compile_ctx;
65478 thr->compile_ctx = &comp_stk.comp_ctx_alloc; /* for duk_error_augment.c */
65479 safe_rc = duk_safe_call(ctx, duk__js_compile_raw, 2 /*nargs*/, 1 /*nret*/);
11fdf7f2 65480 thr->compile_ctx = prev_ctx; /* must restore reliably before returning */
7c673cae
FG
65481
65482 if (safe_rc != DUK_EXEC_SUCCESS) {
7c673cae
FG
65483 duk_throw(ctx);
65484 }
65485
65486 /* [ ... template ] */
65487}
7c673cae
FG
65488/*
65489 * Ecmascript bytecode executor.
65490 */
65491
65492/* include removed: duk_internal.h */
65493
65494/*
11fdf7f2 65495 * Local declarations.
7c673cae
FG
65496 */
65497
11fdf7f2 65498DUK_LOCAL_DECL void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_size_t entry_callstack_top);
7c673cae
FG
65499
65500/*
65501 * Arithmetic, binary, and logical helpers.
65502 *
65503 * Note: there is no opcode for logical AND or logical OR; this is on
65504 * purpose, because the evalution order semantics for them make such
11fdf7f2
TL
65505 * opcodes pretty pointless: short circuiting means they are most
65506 * comfortably implemented as jumps. However, a logical NOT opcode
7c673cae
FG
65507 * is useful.
65508 *
65509 * Note: careful with duk_tval pointers here: they are potentially
11fdf7f2
TL
65510 * invalidated by any DECREF and almost any API call. It's still
65511 * preferable to work without making a copy but that's not always
65512 * possible.
7c673cae
FG
65513 */
65514
65515DUK_LOCAL duk_double_t duk__compute_mod(duk_double_t d1, duk_double_t d2) {
65516 /*
65517 * Ecmascript modulus ('%') does not match IEEE 754 "remainder"
65518 * operation (implemented by remainder() in C99) but does seem
65519 * to match ANSI C fmod().
65520 *
65521 * Compare E5 Section 11.5.3 and "man fmod".
65522 */
65523
65524 return (duk_double_t) DUK_FMOD((double) d1, (double) d2);
65525}
65526
65527DUK_LOCAL void duk__vm_arith_add(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_fast_t idx_z) {
65528 /*
65529 * Addition operator is different from other arithmetic
65530 * operations in that it also provides string concatenation.
65531 * Hence it is implemented separately.
65532 *
65533 * There is a fast path for number addition. Other cases go
65534 * through potentially multiple coercions as described in the
65535 * E5 specification. It may be possible to reduce the number
65536 * of coercions, but this must be done carefully to preserve
65537 * the exact semantics.
65538 *
65539 * E5 Section 11.6.1.
65540 *
65541 * Custom types also have special behavior implemented here.
65542 */
65543
65544 duk_context *ctx = (duk_context *) thr;
65545 duk_double_union du;
65546
65547 DUK_ASSERT(thr != NULL);
65548 DUK_ASSERT(ctx != NULL);
65549 DUK_ASSERT(tv_x != NULL); /* may be reg or const */
65550 DUK_ASSERT(tv_y != NULL); /* may be reg or const */
65551 DUK_ASSERT_DISABLE(idx_z >= 0); /* unsigned */
65552 DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(ctx));
65553
65554 /*
65555 * Fast paths
65556 */
65557
65558#if defined(DUK_USE_FASTINT)
65559 if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
65560 duk_int64_t v1, v2, v3;
65561 duk_int32_t v3_hi;
7c673cae
FG
65562 duk_tval *tv_z;
65563
65564 /* Input values are signed 48-bit so we can detect overflow
65565 * reliably from high bits or just a comparison.
65566 */
65567
65568 v1 = DUK_TVAL_GET_FASTINT(tv_x);
65569 v2 = DUK_TVAL_GET_FASTINT(tv_y);
65570 v3 = v1 + v2;
65571 v3_hi = (duk_int32_t) (v3 >> 32);
65572 if (DUK_LIKELY(v3_hi >= -0x8000LL && v3_hi <= 0x7fffLL)) {
65573 tv_z = thr->valstack_bottom + idx_z;
11fdf7f2 65574 DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, v3); /* side effects */
7c673cae
FG
65575 return;
65576 } else {
65577 /* overflow, fall through */
65578 ;
65579 }
65580 }
65581#endif /* DUK_USE_FASTINT */
65582
65583 if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
7c673cae
FG
65584 duk_tval *tv_z;
65585
65586 du.d = DUK_TVAL_GET_NUMBER(tv_x) + DUK_TVAL_GET_NUMBER(tv_y);
65587 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
65588 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
65589
65590 tv_z = thr->valstack_bottom + idx_z;
11fdf7f2 65591 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, du.d); /* side effects */
7c673cae
FG
65592 return;
65593 }
65594
65595 /*
65596 * Slow path: potentially requires function calls for coercion
65597 */
65598
65599 duk_push_tval(ctx, tv_x);
65600 duk_push_tval(ctx, tv_y);
65601 duk_to_primitive(ctx, -2, DUK_HINT_NONE); /* side effects -> don't use tv_x, tv_y after */
65602 duk_to_primitive(ctx, -1, DUK_HINT_NONE);
65603
65604 /* As a first approximation, buffer values are coerced to strings
65605 * for addition. This means that adding two buffers currently
65606 * results in a string.
65607 */
65608 if (duk_check_type_mask(ctx, -2, DUK_TYPE_MASK_STRING | DUK_TYPE_MASK_BUFFER) ||
65609 duk_check_type_mask(ctx, -1, DUK_TYPE_MASK_STRING | DUK_TYPE_MASK_BUFFER)) {
65610 duk_to_string(ctx, -2);
65611 duk_to_string(ctx, -1);
65612 duk_concat(ctx, 2); /* [... s1 s2] -> [... s1+s2] */
65613 duk_replace(ctx, (duk_idx_t) idx_z); /* side effects */
65614 } else {
65615 duk_double_t d1, d2;
65616
65617 d1 = duk_to_number(ctx, -2);
65618 d2 = duk_to_number(ctx, -1);
65619 DUK_ASSERT(duk_is_number(ctx, -2));
65620 DUK_ASSERT(duk_is_number(ctx, -1));
65621 DUK_ASSERT_DOUBLE_IS_NORMALIZED(d1);
65622 DUK_ASSERT_DOUBLE_IS_NORMALIZED(d2);
65623
65624 du.d = d1 + d2;
65625 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
65626 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
65627
65628 duk_pop_2(ctx);
65629 duk_push_number(ctx, du.d);
65630 duk_replace(ctx, (duk_idx_t) idx_z); /* side effects */
65631 }
65632}
65633
65634DUK_LOCAL 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) {
65635 /*
65636 * Arithmetic operations other than '+' have number-only semantics
65637 * and are implemented here. The separate switch-case here means a
65638 * "double dispatch" of the arithmetic opcode, but saves code space.
65639 *
65640 * E5 Sections 11.5, 11.5.1, 11.5.2, 11.5.3, 11.6, 11.6.1, 11.6.2, 11.6.3.
65641 */
65642
65643 duk_context *ctx = (duk_context *) thr;
7c673cae
FG
65644 duk_tval *tv_z;
65645 duk_double_t d1, d2;
65646 duk_double_union du;
65647
65648 DUK_ASSERT(thr != NULL);
65649 DUK_ASSERT(ctx != NULL);
65650 DUK_ASSERT(tv_x != NULL); /* may be reg or const */
65651 DUK_ASSERT(tv_y != NULL); /* may be reg or const */
65652 DUK_ASSERT_DISABLE(idx_z >= 0); /* unsigned */
65653 DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(ctx));
65654
65655#if defined(DUK_USE_FASTINT)
65656 if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
65657 duk_int64_t v1, v2, v3;
65658 duk_int32_t v3_hi;
65659
65660 v1 = DUK_TVAL_GET_FASTINT(tv_x);
65661 v2 = DUK_TVAL_GET_FASTINT(tv_y);
65662
65663 switch (opcode) {
65664 case DUK_OP_SUB: {
65665 v3 = v1 - v2;
65666 break;
65667 }
65668 case DUK_OP_MUL: {
65669 /* Must ensure result is 64-bit (no overflow); a
65670 * simple and sufficient fast path is to allow only
65671 * 32-bit inputs. Avoid zero inputs to avoid
65672 * negative zero issues (-1 * 0 = -0, for instance).
65673 */
65674 if (v1 >= -0x80000000LL && v1 <= 0x7fffffffLL && v1 != 0 &&
65675 v2 >= -0x80000000LL && v2 <= 0x7fffffffLL && v2 != 0) {
65676 v3 = v1 * v2;
65677 } else {
65678 goto skip_fastint;
65679 }
65680 break;
65681 }
65682 case DUK_OP_DIV: {
65683 /* Don't allow a zero divisor. Fast path check by
65684 * "verifying" with multiplication. Also avoid zero
65685 * dividend to avoid negative zero issues (0 / -1 = -0
65686 * for instance).
65687 */
65688 if (v1 == 0 || v2 == 0) {
65689 goto skip_fastint;
65690 }
65691 v3 = v1 / v2;
65692 if (v3 * v2 != v1) {
65693 goto skip_fastint;
65694 }
65695 break;
65696 }
65697 case DUK_OP_MOD: {
65698 /* Don't allow a zero divisor. Restrict both v1 and
65699 * v2 to positive values to avoid compiler specific
65700 * behavior.
65701 */
65702 if (v1 < 1 || v2 < 1) {
65703 goto skip_fastint;
65704 }
65705 v3 = v1 % v2;
65706 DUK_ASSERT(v3 >= 0);
65707 DUK_ASSERT(v3 < v2);
65708 DUK_ASSERT(v1 - (v1 / v2) * v2 == v3);
65709 break;
65710 }
65711 default: {
65712 DUK_UNREACHABLE();
65713 goto skip_fastint;
65714 }
65715 }
65716
65717 v3_hi = (duk_int32_t) (v3 >> 32);
65718 if (DUK_LIKELY(v3_hi >= -0x8000LL && v3_hi <= 0x7fffLL)) {
65719 tv_z = thr->valstack_bottom + idx_z;
11fdf7f2 65720 DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, v3); /* side effects */
7c673cae
FG
65721 return;
65722 }
65723 /* fall through if overflow etc */
65724 }
65725 skip_fastint:
65726#endif /* DUK_USE_FASTINT */
65727
65728 if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
65729 /* fast path */
65730 d1 = DUK_TVAL_GET_NUMBER(tv_x);
65731 d2 = DUK_TVAL_GET_NUMBER(tv_y);
65732 } else {
65733 duk_push_tval(ctx, tv_x);
65734 duk_push_tval(ctx, tv_y);
65735 d1 = duk_to_number(ctx, -2); /* side effects */
65736 d2 = duk_to_number(ctx, -1);
65737 DUK_ASSERT(duk_is_number(ctx, -2));
65738 DUK_ASSERT(duk_is_number(ctx, -1));
65739 DUK_ASSERT_DOUBLE_IS_NORMALIZED(d1);
65740 DUK_ASSERT_DOUBLE_IS_NORMALIZED(d2);
65741 duk_pop_2(ctx);
65742 }
65743
65744 switch (opcode) {
65745 case DUK_OP_SUB: {
65746 du.d = d1 - d2;
65747 break;
65748 }
65749 case DUK_OP_MUL: {
65750 du.d = d1 * d2;
65751 break;
65752 }
65753 case DUK_OP_DIV: {
65754 du.d = d1 / d2;
65755 break;
65756 }
65757 case DUK_OP_MOD: {
65758 du.d = duk__compute_mod(d1, d2);
65759 break;
65760 }
65761 default: {
65762 DUK_UNREACHABLE();
65763 du.d = DUK_DOUBLE_NAN; /* should not happen */
65764 break;
65765 }
65766 }
65767
65768 /* important to use normalized NaN with 8-byte tagged types */
65769 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
65770 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
65771
65772 tv_z = thr->valstack_bottom + idx_z;
11fdf7f2 65773 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, du.d); /* side effects */
7c673cae
FG
65774}
65775
65776DUK_LOCAL 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) {
65777 /*
65778 * Binary bitwise operations use different coercions (ToInt32, ToUint32)
65779 * depending on the operation. We coerce the arguments first using
65780 * ToInt32(), and then cast to an 32-bit value if necessary. Note that
65781 * such casts must be correct even if there is no native 32-bit type
65782 * (e.g., duk_int32_t and duk_uint32_t are 64-bit).
65783 *
65784 * E5 Sections 11.10, 11.7.1, 11.7.2, 11.7.3
65785 */
65786
65787 duk_context *ctx = (duk_context *) thr;
7c673cae
FG
65788 duk_tval *tv_z;
65789 duk_int32_t i1, i2, i3;
65790 duk_uint32_t u1, u2, u3;
65791#if defined(DUK_USE_FASTINT)
65792 duk_int64_t fi3;
65793#else
65794 duk_double_t d3;
65795#endif
65796
65797 DUK_ASSERT(thr != NULL);
65798 DUK_ASSERT(ctx != NULL);
65799 DUK_ASSERT(tv_x != NULL); /* may be reg or const */
65800 DUK_ASSERT(tv_y != NULL); /* may be reg or const */
65801 DUK_ASSERT_DISABLE(idx_z >= 0); /* unsigned */
65802 DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(ctx));
65803
65804#if defined(DUK_USE_FASTINT)
65805 if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
65806 i1 = (duk_int32_t) DUK_TVAL_GET_FASTINT_I32(tv_x);
65807 i2 = (duk_int32_t) DUK_TVAL_GET_FASTINT_I32(tv_y);
65808 }
65809 else
65810#endif /* DUK_USE_FASTINT */
65811 {
65812 duk_push_tval(ctx, tv_x);
65813 duk_push_tval(ctx, tv_y);
65814 i1 = duk_to_int32(ctx, -2);
65815 i2 = duk_to_int32(ctx, -1);
65816 duk_pop_2(ctx);
65817 }
65818
65819 switch (opcode) {
65820 case DUK_OP_BAND: {
65821 i3 = i1 & i2;
65822 break;
65823 }
65824 case DUK_OP_BOR: {
65825 i3 = i1 | i2;
65826 break;
65827 }
65828 case DUK_OP_BXOR: {
65829 i3 = i1 ^ i2;
65830 break;
65831 }
65832 case DUK_OP_BASL: {
65833 /* Signed shift, named "arithmetic" (asl) because the result
65834 * is signed, e.g. 4294967295 << 1 -> -2. Note that result
65835 * must be masked.
65836 */
65837
65838 u2 = ((duk_uint32_t) i2) & 0xffffffffUL;
11fdf7f2
TL
65839 i3 = (duk_int32_t) (((duk_uint32_t) i1) << (u2 & 0x1fUL)); /* E5 Section 11.7.1, steps 7 and 8 */
65840 i3 = i3 & ((duk_int32_t) 0xffffffffUL); /* Note: left shift, should mask */
7c673cae
FG
65841 break;
65842 }
65843 case DUK_OP_BASR: {
65844 /* signed shift */
65845
65846 u2 = ((duk_uint32_t) i2) & 0xffffffffUL;
11fdf7f2 65847 i3 = i1 >> (u2 & 0x1fUL); /* E5 Section 11.7.2, steps 7 and 8 */
7c673cae
FG
65848 break;
65849 }
65850 case DUK_OP_BLSR: {
65851 /* unsigned shift */
65852
65853 u1 = ((duk_uint32_t) i1) & 0xffffffffUL;
65854 u2 = ((duk_uint32_t) i2) & 0xffffffffUL;
65855
65856 /* special result value handling */
11fdf7f2 65857 u3 = u1 >> (u2 & 0x1fUL); /* E5 Section 11.7.2, steps 7 and 8 */
7c673cae
FG
65858#if defined(DUK_USE_FASTINT)
65859 fi3 = (duk_int64_t) u3;
65860 goto fastint_result_set;
65861#else
65862 d3 = (duk_double_t) u3;
65863 goto result_set;
65864#endif
65865 }
65866 default: {
65867 DUK_UNREACHABLE();
65868 i3 = 0; /* should not happen */
65869 break;
65870 }
65871 }
65872
65873#if defined(DUK_USE_FASTINT)
65874 /* Result is always fastint compatible. */
11fdf7f2
TL
65875 /* XXX: Set 32-bit result (but must then handle signed and
65876 * unsigned results separately).
65877 */
7c673cae
FG
65878 fi3 = (duk_int64_t) i3;
65879
65880 fastint_result_set:
65881 tv_z = thr->valstack_bottom + idx_z;
11fdf7f2 65882 DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, fi3); /* side effects */
7c673cae
FG
65883#else
65884 d3 = (duk_double_t) i3;
65885
65886 result_set:
65887 DUK_ASSERT(!DUK_ISNAN(d3)); /* 'd3' is never NaN, so no need to normalize */
65888 DUK_ASSERT_DOUBLE_IS_NORMALIZED(d3); /* always normalized */
65889
65890 tv_z = thr->valstack_bottom + idx_z;
11fdf7f2 65891 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, d3); /* side effects */
7c673cae
FG
65892#endif
65893}
65894
65895/* In-place unary operation. */
65896DUK_LOCAL void duk__vm_arith_unary_op(duk_hthread *thr, duk_tval *tv_x, duk_idx_t idx_x, duk_small_uint_fast_t opcode) {
65897 /*
65898 * Arithmetic operations other than '+' have number-only semantics
65899 * and are implemented here. The separate switch-case here means a
65900 * "double dispatch" of the arithmetic opcode, but saves code space.
65901 *
65902 * E5 Sections 11.5, 11.5.1, 11.5.2, 11.5.3, 11.6, 11.6.1, 11.6.2, 11.6.3.
65903 */
65904
65905 duk_context *ctx = (duk_context *) thr;
65906 duk_double_t d1;
65907 duk_double_union du;
65908
65909 DUK_ASSERT(thr != NULL);
65910 DUK_ASSERT(ctx != NULL);
65911 DUK_ASSERT(opcode == DUK_EXTRAOP_UNM || opcode == DUK_EXTRAOP_UNP);
11fdf7f2
TL
65912 DUK_ASSERT(tv_x != NULL);
65913 DUK_ASSERT(idx_x >= 0);
7c673cae
FG
65914
65915#if defined(DUK_USE_FASTINT)
65916 if (DUK_TVAL_IS_FASTINT(tv_x)) {
65917 duk_int64_t v1, v2;
65918
65919 v1 = DUK_TVAL_GET_FASTINT(tv_x);
65920 if (opcode == DUK_EXTRAOP_UNM) {
65921 /* The smallest fastint is no longer 48-bit when
65922 * negated. Positive zero becames negative zero
65923 * (cannot be represented) when negated.
65924 */
65925 if (DUK_LIKELY(v1 != DUK_FASTINT_MIN && v1 != 0)) {
65926 v2 = -v1;
65927 DUK_TVAL_SET_FASTINT(tv_x, v2); /* no refcount changes */
65928 return;
65929 }
65930 } else {
65931 /* ToNumber() for a fastint is a no-op. */
65932 DUK_ASSERT(opcode == DUK_EXTRAOP_UNP);
65933 return;
65934 }
65935 /* fall through if overflow etc */
65936 }
65937#endif /* DUK_USE_FASTINT */
65938
65939 if (!DUK_TVAL_IS_NUMBER(tv_x)) {
65940 duk_to_number(ctx, idx_x); /* side effects, perform in-place */
11fdf7f2 65941 tv_x = DUK_GET_TVAL_POSIDX(ctx, idx_x);
7c673cae
FG
65942 DUK_ASSERT(tv_x != NULL);
65943 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_x));
65944 }
65945
65946 d1 = DUK_TVAL_GET_NUMBER(tv_x);
65947 if (opcode == DUK_EXTRAOP_UNM) {
65948 du.d = -d1;
65949 } else {
65950 /* ToNumber() for a double is a no-op. */
65951 DUK_ASSERT(opcode == DUK_EXTRAOP_UNP);
65952 du.d = d1;
65953 }
65954 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du); /* mandatory if du.d is a NaN */
65955
65956 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
65957
65958#if defined(DUK_USE_FASTINT)
65959 /* Unary plus is used to force a fastint check, so must include
65960 * downgrade check.
65961 */
65962 DUK_TVAL_SET_NUMBER_CHKFAST(tv_x, du.d); /* no refcount changes */
65963#else
65964 DUK_TVAL_SET_NUMBER(tv_x, du.d); /* no refcount changes */
65965#endif
65966}
65967
11fdf7f2 65968DUK_LOCAL void duk__vm_bitwise_not(duk_hthread *thr, duk_tval *tv_x, duk_uint_fast_t idx_z) {
7c673cae
FG
65969 /*
65970 * E5 Section 11.4.8
65971 */
65972
65973 duk_context *ctx = (duk_context *) thr;
7c673cae
FG
65974 duk_tval *tv_z;
65975 duk_int32_t i1, i2;
65976#if !defined(DUK_USE_FASTINT)
65977 duk_double_t d2;
65978#endif
65979
65980 DUK_ASSERT(thr != NULL);
65981 DUK_ASSERT(ctx != NULL);
65982 DUK_ASSERT(tv_x != NULL); /* may be reg or const */
65983 DUK_ASSERT_DISABLE(idx_z >= 0);
65984 DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(ctx));
65985
65986#if defined(DUK_USE_FASTINT)
65987 if (DUK_TVAL_IS_FASTINT(tv_x)) {
65988 i1 = (duk_int32_t) DUK_TVAL_GET_FASTINT_I32(tv_x);
65989 }
65990 else
65991#endif /* DUK_USE_FASTINT */
65992 {
65993 duk_push_tval(ctx, tv_x);
65994 i1 = duk_to_int32(ctx, -1);
65995 duk_pop(ctx);
65996 }
65997
65998 i2 = ~i1;
65999
66000#if defined(DUK_USE_FASTINT)
66001 /* Result is always fastint compatible. */
66002 tv_z = thr->valstack_bottom + idx_z;
11fdf7f2 66003 DUK_TVAL_SET_FASTINT_I32_UPDREF(thr, tv_z, i2); /* side effects */
7c673cae
FG
66004#else
66005 d2 = (duk_double_t) i2;
66006
66007 DUK_ASSERT(!DUK_ISNAN(d2)); /* 'val' is never NaN, so no need to normalize */
66008 DUK_ASSERT_DOUBLE_IS_NORMALIZED(d2); /* always normalized */
66009
66010 tv_z = thr->valstack_bottom + idx_z;
11fdf7f2 66011 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, d2); /* side effects */
7c673cae
FG
66012#endif
66013}
66014
66015DUK_LOCAL void duk__vm_logical_not(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_z) {
66016 /*
66017 * E5 Section 11.4.9
66018 */
66019
7c673cae
FG
66020 duk_bool_t res;
66021
66022 DUK_ASSERT(thr != NULL);
66023 DUK_ASSERT(tv_x != NULL); /* may be reg or const */
66024 DUK_ASSERT(tv_z != NULL); /* reg */
66025
66026 DUK_UNREF(thr); /* w/o refcounts */
66027
66028 /* ToBoolean() does not require any operations with side effects so
66029 * we can do it efficiently. For footprint it would be better to use
66030 * duk_js_toboolean() and then push+replace to the result slot.
66031 */
66032 res = duk_js_toboolean(tv_x); /* does not modify tv_x */
66033 DUK_ASSERT(res == 0 || res == 1);
66034 res ^= 1;
11fdf7f2 66035 DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv_z, res); /* side effects */
7c673cae
FG
66036}
66037
66038/*
11fdf7f2 66039 * Longjmp and other control flow transfer for the bytecode executor.
7c673cae 66040 *
11fdf7f2
TL
66041 * The longjmp handler can handle all longjmp types: error, yield, and
66042 * resume (pseudotypes are never actually thrown).
7c673cae 66043 *
11fdf7f2
TL
66044 * Error policy for longjmp: should not ordinarily throw errors; if errors
66045 * occur (e.g. due to out-of-memory) they bubble outwards rather than being
66046 * handled recursively.
7c673cae
FG
66047 */
66048
7c673cae 66049#define DUK__LONGJMP_RESTART 0 /* state updated, restart bytecode execution */
11fdf7f2
TL
66050#define DUK__LONGJMP_RETHROW 1 /* exit bytecode executor by rethrowing an error to caller */
66051
66052#define DUK__RETHAND_RESTART 0 /* state updated, restart bytecode execution */
66053#define DUK__RETHAND_FINISHED 1 /* exit bytecode execution with return value */
7c673cae 66054
11fdf7f2
TL
66055/* XXX: optimize reconfig valstack operations so that resize, clamp, and setting
66056 * top are combined into one pass.
66057 */
66058
66059/* Reconfigure value stack for return to an Ecmascript function at 'act_idx'. */
66060DUK_LOCAL void duk__reconfig_valstack_ecma_return(duk_hthread *thr, duk_size_t act_idx) {
66061 duk_activation *act;
7c673cae 66062 duk_hcompiledfunction *h_func;
11fdf7f2 66063 duk_idx_t clamp_top;
7c673cae
FG
66064
66065 DUK_ASSERT(thr != NULL);
66066 DUK_ASSERT_DISABLE(act_idx >= 0); /* unsigned */
66067 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + act_idx) != NULL);
66068 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + act_idx)));
66069 DUK_ASSERT_DISABLE(thr->callstack[act_idx].idx_retval >= 0); /* unsigned */
66070
11fdf7f2
TL
66071 /* Clamp so that values at 'clamp_top' and above are wiped and won't
66072 * retain reachable garbage. Then extend to 'nregs' because we're
66073 * returning to an Ecmascript function.
7c673cae 66074 */
7c673cae 66075
11fdf7f2
TL
66076 act = thr->callstack + act_idx;
66077 h_func = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
7c673cae 66078
11fdf7f2
TL
66079 thr->valstack_bottom = thr->valstack + act->idx_bottom;
66080 DUK_ASSERT(act->idx_retval >= act->idx_bottom);
66081 clamp_top = (duk_idx_t) (act->idx_retval - act->idx_bottom + 1); /* +1 = one retval */
66082 duk_set_top((duk_context *) thr, clamp_top);
66083 act = NULL;
7c673cae
FG
66084
66085 (void) duk_valstack_resize_raw((duk_context *) thr,
11fdf7f2
TL
66086 (thr->valstack_bottom - thr->valstack) + /* bottom of current func */
66087 h_func->nregs + /* reg count */
66088 DUK_VALSTACK_INTERNAL_EXTRA, /* + spare */
66089 DUK_VSRESIZE_FLAG_SHRINK | /* flags */
7c673cae
FG
66090 0 /* no compact */ |
66091 DUK_VSRESIZE_FLAG_THROW);
66092
66093 duk_set_top((duk_context *) thr, h_func->nregs);
66094}
66095
11fdf7f2
TL
66096DUK_LOCAL void duk__reconfig_valstack_ecma_catcher(duk_hthread *thr, duk_size_t act_idx, duk_size_t cat_idx) {
66097 duk_activation *act;
66098 duk_catcher *cat;
66099 duk_hcompiledfunction *h_func;
66100 duk_idx_t clamp_top;
66101
66102 DUK_ASSERT(thr != NULL);
66103 DUK_ASSERT_DISABLE(act_idx >= 0); /* unsigned */
66104 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + act_idx) != NULL);
66105 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + act_idx)));
66106 DUK_ASSERT_DISABLE(thr->callstack[act_idx].idx_retval >= 0); /* unsigned */
7c673cae 66107
11fdf7f2
TL
66108 act = thr->callstack + act_idx;
66109 cat = thr->catchstack + cat_idx;
66110 h_func = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
7c673cae 66111
11fdf7f2
TL
66112 thr->valstack_bottom = thr->valstack + act->idx_bottom;
66113 DUK_ASSERT(cat->idx_base >= act->idx_bottom);
66114 clamp_top = (duk_idx_t) (cat->idx_base - act->idx_bottom + 2); /* +2 = catcher value, catcher lj_type */
66115 duk_set_top((duk_context *) thr, clamp_top);
66116 act = NULL;
66117 cat = NULL;
66118
66119 (void) duk_valstack_resize_raw((duk_context *) thr,
66120 (thr->valstack_bottom - thr->valstack) + /* bottom of current func */
66121 h_func->nregs + /* reg count */
66122 DUK_VALSTACK_INTERNAL_EXTRA, /* + spare */
66123 DUK_VSRESIZE_FLAG_SHRINK | /* flags */
66124 0 /* no compact */ |
66125 DUK_VSRESIZE_FLAG_THROW);
66126
66127 duk_set_top((duk_context *) thr, h_func->nregs);
66128}
66129
66130/* Set catcher regs: idx_base+0 = value, idx_base+1 = lj_type. */
66131DUK_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) {
66132 duk_tval *tv1;
7c673cae 66133
11fdf7f2
TL
66134 DUK_ASSERT(thr != NULL);
66135 DUK_ASSERT(tv_val_unstable != NULL);
7c673cae
FG
66136
66137 tv1 = thr->valstack + thr->catchstack[cat_idx].idx_base;
11fdf7f2
TL
66138 DUK_ASSERT(tv1 < thr->valstack_top);
66139 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv_val_unstable); /* side effects */
7c673cae
FG
66140
66141 tv1 = thr->valstack + thr->catchstack[cat_idx].idx_base + 1;
11fdf7f2 66142 DUK_ASSERT(tv1 < thr->valstack_top);
7c673cae 66143
11fdf7f2
TL
66144 DUK_TVAL_SET_FASTINT_U32_UPDREF(thr, tv1, (duk_uint32_t) lj_type); /* side effects */
66145}
66146
66147DUK_LOCAL void duk__handle_catch(duk_hthread *thr, duk_size_t cat_idx, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) {
66148 duk_context *ctx;
66149 duk_activation *act;
66150
66151 DUK_ASSERT(thr != NULL);
66152 DUK_ASSERT(tv_val_unstable != NULL);
66153 ctx = (duk_context *) thr;
66154
66155 duk__set_catcher_regs(thr, cat_idx, tv_val_unstable, lj_type);
7c673cae
FG
66156
66157 duk_hthread_catchstack_unwind(thr, cat_idx + 1);
66158 duk_hthread_callstack_unwind(thr, thr->catchstack[cat_idx].callstack_index + 1);
66159
7c673cae
FG
66160 DUK_ASSERT(thr->callstack_top >= 1);
66161 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL);
66162 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)));
66163
11fdf7f2 66164 duk__reconfig_valstack_ecma_catcher(thr, thr->callstack_top - 1, cat_idx);
7c673cae 66165
11fdf7f2
TL
66166 DUK_ASSERT(thr->callstack_top >= 1);
66167 act = thr->callstack + thr->callstack_top - 1;
66168 act->curr_pc = thr->catchstack[cat_idx].pc_base + 0; /* +0 = catch */
66169 act = NULL;
7c673cae
FG
66170
66171 /*
66172 * If entering a 'catch' block which requires an automatic
66173 * catch variable binding, create the lexical environment.
66174 *
66175 * The binding is mutable (= writable) but not deletable.
66176 * Step 4 for the catch production in E5 Section 12.14;
66177 * no value is given for CreateMutableBinding 'D' argument,
66178 * which implies the binding is not deletable.
66179 */
66180
11fdf7f2 66181 if (DUK_CAT_HAS_CATCH_BINDING_ENABLED(&thr->catchstack[cat_idx])) {
7c673cae
FG
66182 duk_hobject *new_env;
66183 duk_hobject *act_lex_env;
66184
66185 DUK_DDD(DUK_DDDPRINT("catcher has an automatic catch binding"));
66186
66187 /* Note: 'act' is dangerous here because it may get invalidate at many
66188 * points, so we re-lookup it multiple times.
66189 */
66190 DUK_ASSERT(thr->callstack_top >= 1);
66191 act = thr->callstack + thr->callstack_top - 1;
66192
66193 if (act->lex_env == NULL) {
66194 DUK_ASSERT(act->var_env == NULL);
66195 DUK_DDD(DUK_DDDPRINT("delayed environment initialization"));
66196
66197 /* this may have side effects, so re-lookup act */
66198 duk_js_init_activation_environment_records_delayed(thr, act);
66199 act = thr->callstack + thr->callstack_top - 1;
66200 }
66201 DUK_ASSERT(act->lex_env != NULL);
66202 DUK_ASSERT(act->var_env != NULL);
66203 DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
66204 DUK_UNREF(act); /* unreferenced without assertions */
66205
66206 act = thr->callstack + thr->callstack_top - 1;
66207 act_lex_env = act->lex_env;
66208 act = NULL; /* invalidated */
66209
66210 (void) duk_push_object_helper_proto(ctx,
66211 DUK_HOBJECT_FLAG_EXTENSIBLE |
66212 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
66213 act_lex_env);
11fdf7f2 66214 new_env = DUK_GET_HOBJECT_NEGIDX(ctx, -1);
7c673cae
FG
66215 DUK_ASSERT(new_env != NULL);
66216 DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO", (duk_heaphdr *) new_env));
66217
66218 /* Note: currently the catch binding is handled without a register
66219 * binding because we don't support dynamic register bindings (they
66220 * must be fixed for an entire function). So, there is no need to
66221 * record regbases etc.
66222 */
66223
66224 DUK_ASSERT(thr->catchstack[cat_idx].h_varname != NULL);
66225 duk_push_hstring(ctx, thr->catchstack[cat_idx].h_varname);
11fdf7f2 66226 duk_push_tval(ctx, thr->valstack + thr->catchstack[cat_idx].idx_base);
7c673cae
FG
66227 duk_xdef_prop(ctx, -3, DUK_PROPDESC_FLAGS_W); /* writable, not configurable */
66228
66229 act = thr->callstack + thr->callstack_top - 1;
66230 act->lex_env = new_env;
66231 DUK_HOBJECT_INCREF(thr, new_env); /* reachable through activation */
66232
66233 DUK_CAT_SET_LEXENV_ACTIVE(&thr->catchstack[cat_idx]);
66234
66235 duk_pop(ctx);
66236
66237 DUK_DDD(DUK_DDDPRINT("new_env finished: %!iO", (duk_heaphdr *) new_env));
66238 }
66239
11fdf7f2 66240 DUK_CAT_CLEAR_CATCH_ENABLED(&thr->catchstack[cat_idx]);
7c673cae
FG
66241}
66242
11fdf7f2 66243DUK_LOCAL void duk__handle_finally(duk_hthread *thr, duk_size_t cat_idx, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) {
7c673cae
FG
66244 duk_activation *act;
66245
7c673cae 66246 DUK_ASSERT(thr != NULL);
11fdf7f2
TL
66247 DUK_ASSERT(tv_val_unstable != NULL);
66248
66249 duk__set_catcher_regs(thr, cat_idx, tv_val_unstable, lj_type);
66250
66251 duk_hthread_catchstack_unwind(thr, cat_idx + 1); /* cat_idx catcher is kept, even for finally */
66252 duk_hthread_callstack_unwind(thr, thr->catchstack[cat_idx].callstack_index + 1);
66253
7c673cae 66254 DUK_ASSERT(thr->callstack_top >= 1);
11fdf7f2
TL
66255 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL);
66256 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)));
7c673cae 66257
11fdf7f2
TL
66258 duk__reconfig_valstack_ecma_catcher(thr, thr->callstack_top - 1, cat_idx);
66259
66260 DUK_ASSERT(thr->callstack_top >= 1);
66261 act = thr->callstack + thr->callstack_top - 1;
66262 act->curr_pc = thr->catchstack[cat_idx].pc_base + 1; /* +1 = finally */
66263 act = NULL;
66264
66265 DUK_CAT_CLEAR_FINALLY_ENABLED(&thr->catchstack[cat_idx]);
66266}
66267
66268DUK_LOCAL void duk__handle_label(duk_hthread *thr, duk_size_t cat_idx, duk_small_uint_t lj_type) {
66269 duk_activation *act;
66270
66271 DUK_ASSERT(thr != NULL);
66272
66273 DUK_ASSERT(thr->callstack_top >= 1);
7c673cae
FG
66274 act = thr->callstack + thr->callstack_top - 1;
66275
66276 DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
66277 DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(act)));
66278
66279 /* +0 = break, +1 = continue */
11fdf7f2 66280 act->curr_pc = thr->catchstack[cat_idx].pc_base + (lj_type == DUK_LJ_TYPE_CONTINUE ? 1 : 0);
7c673cae
FG
66281 act = NULL; /* invalidated */
66282
66283 duk_hthread_catchstack_unwind(thr, cat_idx + 1); /* keep label catcher */
66284 /* no need to unwind callstack */
66285
66286 /* valstack should not need changes */
66287#if defined(DUK_USE_ASSERTIONS)
11fdf7f2 66288 DUK_ASSERT(thr->callstack_top >= 1);
7c673cae
FG
66289 act = thr->callstack + thr->callstack_top - 1;
66290 DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) ==
66291 (duk_size_t) ((duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act))->nregs);
66292#endif
66293}
66294
11fdf7f2
TL
66295/* Called for handling both a longjmp() with type DUK_LJ_TYPE_YIELD and
66296 * when a RETURN opcode terminates a thread and yields to the resumer.
7c673cae 66297 */
11fdf7f2 66298DUK_LOCAL void duk__handle_yield(duk_hthread *thr, duk_hthread *resumer, duk_size_t act_idx, duk_tval *tv_val_unstable) {
7c673cae
FG
66299 duk_tval *tv1;
66300
11fdf7f2
TL
66301 DUK_ASSERT(thr != NULL);
66302 DUK_ASSERT(resumer != NULL);
66303 DUK_ASSERT(tv_val_unstable != NULL);
7c673cae
FG
66304 DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack + act_idx) != NULL);
66305 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(resumer->callstack + act_idx))); /* resume caller must be an ecmascript func */
66306
7c673cae 66307 tv1 = resumer->valstack + resumer->callstack[act_idx].idx_retval; /* return value from Duktape.Thread.resume() */
11fdf7f2 66308 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv_val_unstable); /* side effects */
7c673cae
FG
66309
66310 duk_hthread_callstack_unwind(resumer, act_idx + 1); /* unwind to 'resume' caller */
66311
66312 /* no need to unwind catchstack */
11fdf7f2 66313 duk__reconfig_valstack_ecma_return(resumer, act_idx);
7c673cae
FG
66314
66315 /* caller must change active thread, and set thr->resumer to NULL */
66316}
66317
66318DUK_LOCAL
66319duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
66320 duk_hthread *entry_thread,
66321 duk_size_t entry_callstack_top) {
7c673cae
FG
66322 duk_size_t entry_callstack_index;
66323 duk_small_uint_t retval = DUK__LONGJMP_RESTART;
66324
66325 DUK_ASSERT(thr != NULL);
66326 DUK_ASSERT(entry_thread != NULL);
66327 DUK_ASSERT(entry_callstack_top > 0); /* guarantees entry_callstack_top - 1 >= 0 */
66328
66329 entry_callstack_index = entry_callstack_top - 1;
66330
66331 /* 'thr' is the current thread, as no-one resumes except us and we
66332 * switch 'thr' in that case.
66333 */
11fdf7f2 66334 DUK_ASSERT(thr == thr->heap->curr_thread);
7c673cae
FG
66335
66336 /*
66337 * (Re)try handling the longjmp.
66338 *
66339 * A longjmp handler may convert the longjmp to a different type and
66340 * "virtually" rethrow by goto'ing to 'check_longjmp'. Before the goto,
66341 * the following must be updated:
66342 * - the heap 'lj' state
66343 * - 'thr' must reflect the "throwing" thread
66344 */
66345
66346 check_longjmp:
66347
66348 DUK_DD(DUK_DDPRINT("handling longjmp: type=%ld, value1=%!T, value2=%!T, iserror=%ld",
66349 (long) thr->heap->lj.type,
66350 (duk_tval *) &thr->heap->lj.value1,
66351 (duk_tval *) &thr->heap->lj.value2,
66352 (long) thr->heap->lj.iserror));
66353
66354 switch (thr->heap->lj.type) {
66355
66356 case DUK_LJ_TYPE_RESUME: {
66357 /*
66358 * Note: lj.value1 is 'value', lj.value2 is 'resumee'.
66359 * This differs from YIELD.
66360 */
66361
66362 duk_tval *tv;
66363 duk_tval *tv2;
66364 duk_size_t act_idx;
66365 duk_hthread *resumee;
66366
66367 /* duk_bi_duk_object_yield() and duk_bi_duk_object_resume() ensure all of these are met */
66368
66369 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); /* unchanged by Duktape.Thread.resume() */
66370 DUK_ASSERT(thr->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */
66371 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL &&
66372 DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)) &&
66373 ((duk_hnativefunction *) DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))->func == duk_bi_thread_resume);
66374 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL &&
66375 DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2))); /* an Ecmascript function */
66376 DUK_ASSERT_DISABLE((thr->callstack + thr->callstack_top - 2)->idx_retval >= 0); /* unsigned */
66377
66378 tv = &thr->heap->lj.value2; /* resumee */
66379 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
66380 DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL);
66381 DUK_ASSERT(DUK_HOBJECT_IS_THREAD(DUK_TVAL_GET_OBJECT(tv)));
66382 resumee = (duk_hthread *) DUK_TVAL_GET_OBJECT(tv);
66383
66384 DUK_ASSERT(resumee != NULL);
66385 DUK_ASSERT(resumee->resumer == NULL);
66386 DUK_ASSERT(resumee->state == DUK_HTHREAD_STATE_INACTIVE ||
66387 resumee->state == DUK_HTHREAD_STATE_YIELDED); /* checked by Duktape.Thread.resume() */
66388 DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED ||
66389 resumee->callstack_top >= 2); /* YIELDED: Ecmascript activation + Duktape.Thread.yield() activation */
66390 DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED ||
66391 (DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 1) != NULL &&
66392 DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 1)) &&
66393 ((duk_hnativefunction *) DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 1))->func == duk_bi_thread_yield));
66394 DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED ||
66395 (DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 2) != NULL &&
66396 DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 2)))); /* an Ecmascript function */
66397 DUK_ASSERT_DISABLE(resumee->state != DUK_HTHREAD_STATE_YIELDED ||
66398 (resumee->callstack + resumee->callstack_top - 2)->idx_retval >= 0); /* idx_retval unsigned */
66399 DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_INACTIVE ||
66400 resumee->callstack_top == 0); /* INACTIVE: no activation, single function value on valstack */
66401 DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_INACTIVE ||
66402 (resumee->valstack_top == resumee->valstack + 1 &&
66403 DUK_TVAL_IS_OBJECT(resumee->valstack_top - 1) &&
66404 DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_TVAL_GET_OBJECT(resumee->valstack_top - 1))));
66405
66406 if (thr->heap->lj.iserror) {
66407 /*
66408 * Throw the error in the resumed thread's context; the
66409 * error value is pushed onto the resumee valstack.
66410 *
66411 * Note: the callstack of the target may empty in this case
66412 * too (i.e. the target thread has never been resumed). The
66413 * value stack will contain the initial function in that case,
66414 * which we simply ignore.
66415 */
66416
66417 resumee->resumer = thr;
66418 resumee->state = DUK_HTHREAD_STATE_RUNNING;
66419 thr->state = DUK_HTHREAD_STATE_RESUMED;
66420 DUK_HEAP_SWITCH_THREAD(thr->heap, resumee);
66421 thr = resumee;
66422
66423 thr->heap->lj.type = DUK_LJ_TYPE_THROW;
66424
66425 /* thr->heap->lj.value1 is already the value to throw */
66426 /* thr->heap->lj.value2 is 'thread', will be wiped out at the end */
66427
66428 DUK_ASSERT(thr->heap->lj.iserror); /* already set */
66429
66430 DUK_DD(DUK_DDPRINT("-> resume with an error, converted to a throw in the resumee, propagate"));
66431 goto check_longjmp;
66432 } else if (resumee->state == DUK_HTHREAD_STATE_YIELDED) {
66433 act_idx = resumee->callstack_top - 2; /* Ecmascript function */
66434 DUK_ASSERT_DISABLE(resumee->callstack[act_idx].idx_retval >= 0); /* unsigned */
66435
66436 tv = resumee->valstack + resumee->callstack[act_idx].idx_retval; /* return value from Duktape.Thread.yield() */
66437 DUK_ASSERT(tv >= resumee->valstack && tv < resumee->valstack_top);
66438 tv2 = &thr->heap->lj.value1;
11fdf7f2 66439 DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv2); /* side effects */
7c673cae
FG
66440
66441 duk_hthread_callstack_unwind(resumee, act_idx + 1); /* unwind to 'yield' caller */
66442
66443 /* no need to unwind catchstack */
66444
11fdf7f2 66445 duk__reconfig_valstack_ecma_return(resumee, act_idx);
7c673cae
FG
66446
66447 resumee->resumer = thr;
66448 resumee->state = DUK_HTHREAD_STATE_RUNNING;
66449 thr->state = DUK_HTHREAD_STATE_RESUMED;
66450 DUK_HEAP_SWITCH_THREAD(thr->heap, resumee);
66451#if 0
66452 thr = resumee; /* not needed, as we exit right away */
66453#endif
66454 DUK_DD(DUK_DDPRINT("-> resume with a value, restart execution in resumee"));
66455 retval = DUK__LONGJMP_RESTART;
66456 goto wipe_and_return;
66457 } else {
66458 duk_small_uint_t call_flags;
66459 duk_bool_t setup_rc;
66460
66461 /* resumee: [... initial_func] (currently actually: [initial_func]) */
66462
66463 duk_push_undefined((duk_context *) resumee);
66464 tv = &thr->heap->lj.value1;
66465 duk_push_tval((duk_context *) resumee, tv);
66466
66467 /* resumee: [... initial_func undefined(= this) resume_value ] */
66468
66469 call_flags = DUK_CALL_FLAG_IS_RESUME; /* is resume, not a tail call */
66470
66471 setup_rc = duk_handle_ecma_call_setup(resumee,
66472 1, /* num_stack_args */
66473 call_flags); /* call_flags */
66474 if (setup_rc == 0) {
66475 /* Shouldn't happen but check anyway. */
11fdf7f2 66476 DUK_ERROR_INTERNAL_DEFMSG(thr);
7c673cae
FG
66477 }
66478
66479 resumee->resumer = thr;
66480 resumee->state = DUK_HTHREAD_STATE_RUNNING;
66481 thr->state = DUK_HTHREAD_STATE_RESUMED;
66482 DUK_HEAP_SWITCH_THREAD(thr->heap, resumee);
66483#if 0
66484 thr = resumee; /* not needed, as we exit right away */
66485#endif
66486 DUK_DD(DUK_DDPRINT("-> resume with a value, restart execution in resumee"));
66487 retval = DUK__LONGJMP_RESTART;
66488 goto wipe_and_return;
66489 }
66490 DUK_UNREACHABLE();
66491 break; /* never here */
66492 }
66493
66494 case DUK_LJ_TYPE_YIELD: {
66495 /*
66496 * Currently only allowed only if yielding thread has only
66497 * Ecmascript activations (except for the Duktape.Thread.yield()
66498 * call at the callstack top) and none of them constructor
66499 * calls.
66500 *
66501 * This excludes the 'entry' thread which will always have
66502 * a preventcount > 0.
66503 */
66504
66505 duk_hthread *resumer;
66506
66507 /* duk_bi_duk_object_yield() and duk_bi_duk_object_resume() ensure all of these are met */
66508
66509 DUK_ASSERT(thr != entry_thread); /* Duktape.Thread.yield() should prevent */
66510 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); /* unchanged from Duktape.Thread.yield() */
66511 DUK_ASSERT(thr->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.yield() activation */
66512 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL &&
66513 DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)) &&
66514 ((duk_hnativefunction *) DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))->func == duk_bi_thread_yield);
66515 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL &&
66516 DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2))); /* an Ecmascript function */
66517 DUK_ASSERT_DISABLE((thr->callstack + thr->callstack_top - 2)->idx_retval >= 0); /* unsigned */
66518
66519 resumer = thr->resumer;
66520
66521 DUK_ASSERT(resumer != NULL);
66522 DUK_ASSERT(resumer->state == DUK_HTHREAD_STATE_RESUMED); /* written by a previous RESUME handling */
66523 DUK_ASSERT(resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */
66524 DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 1) != NULL &&
66525 DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 1)) &&
66526 ((duk_hnativefunction *) DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 1))->func == duk_bi_thread_resume);
66527 DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 2) != NULL &&
66528 DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 2))); /* an Ecmascript function */
66529 DUK_ASSERT_DISABLE((resumer->callstack + resumer->callstack_top - 2)->idx_retval >= 0); /* unsigned */
66530
66531 if (thr->heap->lj.iserror) {
66532 thr->state = DUK_HTHREAD_STATE_YIELDED;
66533 thr->resumer = NULL;
66534 resumer->state = DUK_HTHREAD_STATE_RUNNING;
66535 DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
66536 thr = resumer;
66537
66538 thr->heap->lj.type = DUK_LJ_TYPE_THROW;
66539 /* lj.value1 is already set */
66540 DUK_ASSERT(thr->heap->lj.iserror); /* already set */
66541
66542 DUK_DD(DUK_DDPRINT("-> yield an error, converted to a throw in the resumer, propagate"));
66543 goto check_longjmp;
66544 } else {
11fdf7f2 66545 duk__handle_yield(thr, resumer, resumer->callstack_top - 2, &thr->heap->lj.value1);
7c673cae
FG
66546
66547 thr->state = DUK_HTHREAD_STATE_YIELDED;
66548 thr->resumer = NULL;
66549 resumer->state = DUK_HTHREAD_STATE_RUNNING;
66550 DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
66551#if 0
66552 thr = resumer; /* not needed, as we exit right away */
66553#endif
66554
66555 DUK_DD(DUK_DDPRINT("-> yield a value, restart execution in resumer"));
66556 retval = DUK__LONGJMP_RESTART;
66557 goto wipe_and_return;
66558 }
66559 DUK_UNREACHABLE();
66560 break; /* never here */
66561 }
66562
7c673cae
FG
66563 case DUK_LJ_TYPE_THROW: {
66564 /*
66565 * Three possible outcomes:
66566 * * A try or finally catcher is found => resume there.
66567 * (or)
66568 * * The error propagates to the bytecode executor entry
66569 * level (and we're in the entry thread) => rethrow
66570 * with a new longjmp(), after restoring the previous
66571 * catchpoint.
66572 * * The error is not caught in the current thread, so
66573 * the thread finishes with an error. This works like
66574 * a yielded error, except that the thread is finished
66575 * and can no longer be resumed. (There is always a
66576 * resumer in this case.)
66577 *
66578 * Note: until we hit the entry level, there can only be
66579 * Ecmascript activations.
66580 */
66581
66582 duk_catcher *cat;
66583 duk_hthread *resumer;
66584
66585 cat = thr->catchstack + thr->catchstack_top - 1;
66586 while (cat >= thr->catchstack) {
66587 if (thr == entry_thread &&
66588 cat->callstack_index < entry_callstack_index) {
66589 /* entry level reached */
66590 break;
66591 }
66592
66593 if (DUK_CAT_HAS_CATCH_ENABLED(cat)) {
7c673cae
FG
66594 DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF);
66595
11fdf7f2
TL
66596 duk__handle_catch(thr,
66597 cat - thr->catchstack,
66598 &thr->heap->lj.value1,
66599 DUK_LJ_TYPE_THROW);
7c673cae
FG
66600
66601 DUK_DD(DUK_DDPRINT("-> throw caught by a 'catch' clause, restart execution"));
66602 retval = DUK__LONGJMP_RESTART;
66603 goto wipe_and_return;
66604 }
66605
66606 if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
66607 DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF);
66608 DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat));
66609
11fdf7f2
TL
66610 duk__handle_finally(thr,
66611 cat - thr->catchstack,
66612 &thr->heap->lj.value1,
66613 DUK_LJ_TYPE_THROW);
7c673cae
FG
66614
66615 DUK_DD(DUK_DDPRINT("-> throw caught by a 'finally' clause, restart execution"));
66616 retval = DUK__LONGJMP_RESTART;
66617 goto wipe_and_return;
66618 }
66619
66620 cat--;
66621 }
66622
66623 if (thr == entry_thread) {
66624 /* not caught by anything before entry level; rethrow and let the
66625 * final catcher unwind everything
66626 */
66627#if 0
66628 duk_hthread_catchstack_unwind(thr, (cat - thr->catchstack) + 1); /* leave 'cat' as top catcher (also works if catchstack exhausted) */
66629 duk_hthread_callstack_unwind(thr, entry_callstack_index + 1);
66630
66631#endif
66632 DUK_D(DUK_DPRINT("-> throw propagated up to entry level, rethrow and exit bytecode executor"));
66633 retval = DUK__LONGJMP_RETHROW;
66634 goto just_return;
66635 /* Note: MUST NOT wipe_and_return here, as heap->lj must remain intact */
66636 }
66637
11fdf7f2 66638 DUK_DD(DUK_DDPRINT("-> throw not caught by current thread, yield error to resumer and recheck longjmp"));
7c673cae
FG
66639
66640 /* not caught by current thread, thread terminates (yield error to resumer);
66641 * note that this may cause a cascade if the resumer terminates with an uncaught
66642 * exception etc (this is OK, but needs careful testing)
66643 */
66644
66645 DUK_ASSERT(thr->resumer != NULL);
66646 DUK_ASSERT(thr->resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */
66647 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1) != NULL &&
66648 DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1)) &&
66649 ((duk_hnativefunction *) DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */
66650 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2) != NULL &&
66651 DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2))); /* an Ecmascript function */
66652
66653 resumer = thr->resumer;
66654
66655 /* reset longjmp */
66656
66657 DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW); /* already set */
66658 /* lj.value1 already set */
66659
66660 duk_hthread_terminate(thr); /* updates thread state, minimizes its allocations */
66661 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED);
66662
66663 thr->resumer = NULL;
66664 resumer->state = DUK_HTHREAD_STATE_RUNNING;
66665 DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
66666 thr = resumer;
66667 goto check_longjmp;
66668 }
66669
11fdf7f2
TL
66670 case DUK_LJ_TYPE_BREAK: /* pseudotypes, not used in actual longjmps */
66671 case DUK_LJ_TYPE_CONTINUE:
66672 case DUK_LJ_TYPE_RETURN:
66673 case DUK_LJ_TYPE_NORMAL:
7c673cae
FG
66674 default: {
66675 /* should never happen, but be robust */
66676 DUK_D(DUK_DPRINT("caught unknown longjmp type %ld, treat as internal error", (long) thr->heap->lj.type));
66677 goto convert_to_internal_error;
66678 }
66679
66680 } /* end switch */
66681
66682 DUK_UNREACHABLE();
66683
66684 wipe_and_return:
66685 /* this is not strictly necessary, but helps debugging */
66686 thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
66687 thr->heap->lj.iserror = 0;
66688
11fdf7f2
TL
66689 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */
66690 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */
7c673cae
FG
66691
66692 just_return:
66693 return retval;
66694
66695 convert_to_internal_error:
66696 /* This could also be thrown internally (set the error, goto check_longjmp),
11fdf7f2
TL
66697 * but it's better for internal errors to bubble outwards so that we won't
66698 * infinite loop in this catchpoint.
7c673cae 66699 */
11fdf7f2 66700 DUK_ERROR_INTERNAL_DEFMSG(thr);
7c673cae
FG
66701 DUK_UNREACHABLE();
66702 return retval;
66703}
66704
11fdf7f2
TL
66705/* Handle a BREAK/CONTINUE opcode. Avoid using longjmp() for BREAK/CONTINUE
66706 * handling because it has a measurable performance impact in ordinary
66707 * environments and an extreme impact in Emscripten (GH-342).
7c673cae 66708 */
11fdf7f2
TL
66709DUK_LOCAL void duk__handle_break_or_continue(duk_hthread *thr,
66710 duk_uint_t label_id,
66711 duk_small_uint_t lj_type) {
66712 duk_catcher *cat;
66713 duk_size_t orig_callstack_index;
66714
66715 DUK_ASSERT(thr != NULL);
66716
66717 /*
66718 * Find a matching label catcher or 'finally' catcher in
66719 * the same function.
66720 *
66721 * A label catcher must always exist and will match unless
66722 * a 'finally' captures the break/continue first. It is the
66723 * compiler's responsibility to ensure that labels are used
66724 * correctly.
66725 */
66726
66727 /* Note: thr->catchstack_top may be 0, so that cat < thr->catchstack
66728 * initially. This is OK and intended.
66729 */
66730 cat = thr->catchstack + thr->catchstack_top - 1;
66731 DUK_ASSERT(thr->callstack_top > 0);
66732 orig_callstack_index = thr->callstack_top - 1;
66733
66734 DUK_DDD(DUK_DDDPRINT("handling break/continue with label=%ld, callstack index=%ld",
66735 (long) label_id, (long) cat->callstack_index));
66736
66737 while (cat >= thr->catchstack) {
66738 if (cat->callstack_index != orig_callstack_index) {
66739 break;
66740 }
66741 DUK_DDD(DUK_DDDPRINT("considering catcher %ld: type=%ld label=%ld",
66742 (long) (cat - thr->catchstack),
66743 (long) DUK_CAT_GET_TYPE(cat),
66744 (long) DUK_CAT_GET_LABEL(cat)));
66745
66746 if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF &&
66747 DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
66748 duk_size_t cat_idx;
66749 duk_tval tv_tmp;
66750
66751 cat_idx = (duk_size_t) (cat - thr->catchstack); /* get before side effects */
66752
66753 DUK_TVAL_SET_FASTINT_U32(&tv_tmp, (duk_uint32_t) label_id);
66754 duk__handle_finally(thr, cat_idx, &tv_tmp, lj_type);
66755
66756 DUK_DD(DUK_DDPRINT("-> break/continue caught by 'finally', restart execution"));
66757 return;
66758 }
66759 if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_LABEL &&
66760 (duk_uint_t) DUK_CAT_GET_LABEL(cat) == label_id) {
66761 duk_size_t cat_idx;
66762
66763 cat_idx = (duk_size_t) (cat - thr->catchstack);
66764 duk__handle_label(thr, cat_idx, lj_type);
66765
66766 DUK_DD(DUK_DDPRINT("-> break/continue caught by a label catcher (in the same function), restart execution"));
66767 return;
66768 }
66769 cat--;
66770 }
66771
66772 /* should never happen, but be robust */
66773 DUK_D(DUK_DPRINT("-> break/continue not caught by anything in the current function (should never happen), throw internal error"));
66774 DUK_ERROR_INTERNAL_DEFMSG(thr);
66775 return;
66776}
66777
66778/* Handle a RETURN opcode. Avoid using longjmp() for return handling because
66779 * it has a measurable performance impact in ordinary environments and an extreme
66780 * impact in Emscripten (GH-342). Return value is on value stack top.
7c673cae 66781 */
11fdf7f2
TL
66782DUK_LOCAL duk_small_uint_t duk__handle_return(duk_hthread *thr,
66783 duk_hthread *entry_thread,
66784 duk_size_t entry_callstack_top) {
7c673cae 66785 duk_tval *tv1;
11fdf7f2
TL
66786 duk_tval *tv2;
66787 duk_hthread *resumer;
66788 duk_catcher *cat;
66789 duk_size_t new_cat_top;
66790 duk_size_t orig_callstack_index;
7c673cae 66791
11fdf7f2 66792 /* We can directly access value stack here. */
7c673cae 66793
11fdf7f2
TL
66794 DUK_ASSERT(thr != NULL);
66795 DUK_ASSERT(entry_thread != NULL);
66796 DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
66797 tv1 = thr->valstack_top - 1;
66798 DUK_TVAL_CHKFAST_INPLACE(tv1); /* fastint downgrade check for return values */
66799
66800 /*
66801 * Four possible outcomes:
66802 *
66803 * 1. A 'finally' in the same function catches the 'return'.
66804 * It may continue to propagate when 'finally' is finished,
66805 * or it may be neutralized by 'finally' (both handled by
66806 * ENDFIN).
66807 *
66808 * 2. The return happens at the entry level of the bytecode
66809 * executor, so return from the executor (in C stack).
66810 *
66811 * 3. There is a calling (Ecmascript) activation in the call
66812 * stack => return to it, in the same executor instance.
66813 *
66814 * 4. There is no calling activation, and the thread is
66815 * terminated. There is always a resumer in this case,
66816 * which gets the return value similarly to a 'yield'
66817 * (except that the current thread can no longer be
66818 * resumed).
66819 */
66820
66821 DUK_ASSERT(thr != NULL);
66822 DUK_ASSERT(thr->callstack_top >= 1);
66823 DUK_ASSERT(thr->catchstack != NULL);
66824
66825 /* XXX: does not work if thr->catchstack is NULL */
66826 /* XXX: does not work if thr->catchstack is allocated but lowest pointer */
66827
66828 cat = thr->catchstack + thr->catchstack_top - 1; /* may be < thr->catchstack initially */
66829 DUK_ASSERT(thr->callstack_top > 0); /* ensures callstack_top - 1 >= 0 */
66830 orig_callstack_index = thr->callstack_top - 1;
66831
66832 while (cat >= thr->catchstack) {
66833 if (cat->callstack_index != orig_callstack_index) {
66834 break;
66835 }
66836 if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF &&
66837 DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
66838 duk_size_t cat_idx;
66839
66840 cat_idx = (duk_size_t) (cat - thr->catchstack); /* get before side effects */
66841
66842 DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
66843 duk__handle_finally(thr, cat_idx, thr->valstack_top - 1, DUK_LJ_TYPE_RETURN);
66844
66845 DUK_DD(DUK_DDPRINT("-> return caught by 'finally', restart execution"));
66846 return DUK__RETHAND_RESTART;
66847 }
66848 cat--;
7c673cae 66849 }
11fdf7f2
TL
66850 /* If out of catchstack, cat = thr->catchstack - 1;
66851 * new_cat_top will be 0 in that case.
66852 */
66853 new_cat_top = (duk_size_t) ((cat + 1) - thr->catchstack);
66854 cat = NULL; /* avoid referencing, invalidated */
66855
66856 DUK_DDD(DUK_DDDPRINT("no catcher in catch stack, return to calling activation / yield"));
66857
66858 if (thr == entry_thread &&
66859 thr->callstack_top == entry_callstack_top) {
66860 /* Return to the bytecode executor caller which will unwind stacks.
66861 * Return value is already on the stack top: [ ... retval ].
66862 */
66863
66864 /* XXX: could unwind catchstack here, so that call handling
66865 * didn't need to do that?
66866 */
66867 DUK_DDD(DUK_DDDPRINT("-> return propagated up to entry level, exit bytecode executor"));
66868 return DUK__RETHAND_FINISHED;
7c673cae
FG
66869 }
66870
11fdf7f2
TL
66871 if (thr->callstack_top >= 2) {
66872 /* There is a caller; it MUST be an Ecmascript caller (otherwise it would
66873 * match entry level check)
66874 */
7c673cae 66875
11fdf7f2
TL
66876 DUK_DDD(DUK_DDDPRINT("return to Ecmascript caller, idx_retval=%ld, lj_value1=%!T",
66877 (long) (thr->callstack + thr->callstack_top - 2)->idx_retval,
66878 (duk_tval *) &thr->heap->lj.value1));
66879
66880 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2))); /* must be ecmascript */
66881
66882 tv1 = thr->valstack + (thr->callstack + thr->callstack_top - 2)->idx_retval;
66883 DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
66884 tv2 = thr->valstack_top - 1;
66885 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
66886
66887 DUK_DDD(DUK_DDDPRINT("return value at idx_retval=%ld is %!T",
66888 (long) (thr->callstack + thr->callstack_top - 2)->idx_retval,
66889 (duk_tval *) (thr->valstack + (thr->callstack + thr->callstack_top - 2)->idx_retval)));
66890
66891 duk_hthread_catchstack_unwind(thr, new_cat_top); /* leave 'cat' as top catcher (also works if catchstack exhausted) */
66892 duk_hthread_callstack_unwind(thr, thr->callstack_top - 1);
66893 duk__reconfig_valstack_ecma_return(thr, thr->callstack_top - 1);
66894
66895 DUK_DD(DUK_DDPRINT("-> return not intercepted, restart execution in caller"));
66896 return DUK__RETHAND_RESTART;
7c673cae 66897 }
7c673cae 66898
11fdf7f2
TL
66899 DUK_DD(DUK_DDPRINT("no calling activation, thread finishes (similar to yield)"));
66900
66901 DUK_ASSERT(thr->resumer != NULL);
66902 DUK_ASSERT(thr->resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */
66903 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1) != NULL &&
66904 DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1)) &&
66905 ((duk_hnativefunction *) DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */
66906 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2) != NULL &&
66907 DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2))); /* an Ecmascript function */
66908 DUK_ASSERT_DISABLE((thr->resumer->callstack + thr->resumer->callstack_top - 2)->idx_retval >= 0); /* unsigned */
66909 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
66910 DUK_ASSERT(thr->resumer->state == DUK_HTHREAD_STATE_RESUMED);
66911
66912 resumer = thr->resumer;
66913
66914 /* Share yield longjmp handler. */
66915 DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
66916 duk__handle_yield(thr, resumer, resumer->callstack_top - 2, thr->valstack_top - 1);
66917
66918 duk_hthread_terminate(thr); /* updates thread state, minimizes its allocations */
66919 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED);
66920
66921 thr->resumer = NULL;
66922 resumer->state = DUK_HTHREAD_STATE_RUNNING;
66923 DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
7c673cae 66924#if 0
11fdf7f2 66925 thr = resumer; /* not needed */
7c673cae 66926#endif
7c673cae 66927
11fdf7f2
TL
66928 DUK_DD(DUK_DDPRINT("-> return not caught, thread terminated; handle like yield, restart execution in resumer"));
66929 return DUK__RETHAND_RESTART;
7c673cae 66930}
7c673cae
FG
66931
66932/*
66933 * Executor interrupt handling
66934 *
66935 * The handler is called whenever the interrupt countdown reaches zero
66936 * (or below). The handler must perform whatever checks are activated,
66937 * e.g. check for cumulative step count to impose an execution step
66938 * limit or check for breakpoints or other debugger interaction.
66939 *
66940 * When the actions are done, the handler must reinit the interrupt
66941 * init and counter values. The 'init' value must indicate how many
66942 * bytecode instructions are executed before the next interrupt. The
66943 * counter must interface with the bytecode executor loop. Concretely,
66944 * the new init value is normally one higher than the new counter value.
66945 * For instance, to execute exactly one bytecode instruction the init
66946 * value is set to 1 and the counter to 0. If an error is thrown by the
66947 * interrupt handler, the counters are set to the same value (e.g. both
66948 * to 0 to cause an interrupt when the next bytecode instruction is about
66949 * to be executed after error handling).
66950 *
66951 * Maintaining the init/counter value properly is important for accurate
66952 * behavior. For instance, executor step limit needs a cumulative step
66953 * count which is simply computed as a sum of 'init' values. This must
66954 * work accurately even when single stepping.
66955 */
66956
66957#if defined(DUK_USE_INTERRUPT_COUNTER)
66958
66959#define DUK__INT_NOACTION 0 /* no specific action, resume normal execution */
66960#define DUK__INT_RESTART 1 /* must "goto restart_execution", e.g. breakpoints changed */
66961
66962#if defined(DUK_USE_DEBUGGER_SUPPORT)
66963DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_immediate, duk_small_uint_t *out_interrupt_retval) {
66964 duk_context *ctx;
66965 duk_activation *act;
66966 duk_breakpoint *bp;
66967 duk_breakpoint **bp_active;
66968 duk_uint_fast32_t line = 0;
7c673cae
FG
66969 duk_bool_t process_messages;
66970 duk_bool_t processed_messages = 0;
66971
11fdf7f2
TL
66972 DUK_ASSERT(thr->heap->dbg_processing == 0); /* don't re-enter e.g. during Eval */
66973
7c673cae
FG
66974 ctx = (duk_context *) thr;
66975 act = thr->callstack + thr->callstack_top - 1;
66976
66977 /* It might seem that replacing 'thr->heap' with just 'heap' below
66978 * might be a good idea, but it increases code size slightly
66979 * (probably due to unnecessary spilling) at least on x64.
66980 */
66981
66982 /*
66983 * Breakpoint and step state checks
66984 */
66985
66986 if (act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE ||
66987 (thr->heap->dbg_step_thread == thr &&
66988 thr->heap->dbg_step_csindex == thr->callstack_top - 1)) {
66989 line = duk_debug_curr_line(thr);
66990
66991 if (act->prev_line != line) {
66992 /* Stepped? Step out is handled by callstack unwind. */
66993 if ((thr->heap->dbg_step_type == DUK_STEP_TYPE_INTO ||
66994 thr->heap->dbg_step_type == DUK_STEP_TYPE_OVER) &&
66995 (thr->heap->dbg_step_thread == thr) &&
66996 (thr->heap->dbg_step_csindex == thr->callstack_top - 1) &&
66997 (line != thr->heap->dbg_step_startline)) {
66998 DUK_D(DUK_DPRINT("STEP STATE TRIGGERED PAUSE at line %ld",
66999 (long) line));
67000
67001 DUK_HEAP_SET_PAUSED(thr->heap);
67002 }
67003
67004 /* Check for breakpoints only on line transition.
67005 * Breakpoint is triggered when we enter the target
67006 * line from a different line, and the previous line
67007 * was within the same function.
67008 *
67009 * This condition is tricky: the condition used to be
67010 * that transition to -or across- the breakpoint line
67011 * triggered the breakpoint. This seems intuitively
67012 * better because it handles breakpoints on lines with
67013 * no emitted opcodes; but this leads to the issue
67014 * described in: https://github.com/svaarala/duktape/issues/263.
67015 */
67016 bp_active = thr->heap->dbg_breakpoints_active;
67017 for (;;) {
67018 bp = *bp_active++;
67019 if (bp == NULL) {
67020 break;
67021 }
67022
67023 DUK_ASSERT(bp->filename != NULL);
67024 if (act->prev_line != bp->line && line == bp->line) {
67025 DUK_D(DUK_DPRINT("BREAKPOINT TRIGGERED at %!O:%ld",
67026 (duk_heaphdr *) bp->filename, (long) bp->line));
67027
67028 DUK_HEAP_SET_PAUSED(thr->heap);
67029 }
67030 }
67031 } else {
67032 ;
67033 }
67034
67035 act->prev_line = line;
67036 }
67037
67038 /*
67039 * Rate limit check for sending status update or peeking into
67040 * the debug transport. Both can be expensive operations that
67041 * we don't want to do on every opcode.
67042 *
67043 * Making sure the interval remains reasonable on a wide variety
67044 * of targets and bytecode is difficult without a timestamp, so
67045 * we use a Date-provided timestamp for the rate limit check.
67046 * But since it's also expensive to get a timestamp, a bytecode
67047 * counter is used to rate limit getting timestamps.
67048 */
67049
11fdf7f2
TL
67050 process_messages = 0;
67051 if (thr->heap->dbg_state_dirty || thr->heap->dbg_paused || thr->heap->dbg_detaching) {
67052 /* Enter message processing loop for sending Status notifys and
67053 * to finish a pending detach.
67054 */
7c673cae 67055 process_messages = 1;
7c673cae
FG
67056 }
67057
67058 /* XXX: remove heap->dbg_exec_counter, use heap->inst_count_interrupt instead? */
67059 thr->heap->dbg_exec_counter += thr->interrupt_init;
67060 if (thr->heap->dbg_exec_counter - thr->heap->dbg_last_counter >= DUK_HEAP_DBG_RATELIMIT_OPCODES) {
67061 /* Overflow of the execution counter is fine and doesn't break
67062 * anything here.
67063 */
67064
67065 duk_double_t now, diff_last;
67066
67067 thr->heap->dbg_last_counter = thr->heap->dbg_exec_counter;
67068 now = DUK_USE_DATE_GET_NOW(ctx);
67069
67070 diff_last = now - thr->heap->dbg_last_time;
67071 if (diff_last < 0.0 || diff_last >= (duk_double_t) DUK_HEAP_DBG_RATELIMIT_MILLISECS) {
67072 /* Negative value checked so that a "time jump" works
67073 * reasonably.
67074 *
67075 * Same interval is now used for status sending and
67076 * peeking.
67077 */
67078
67079 thr->heap->dbg_last_time = now;
11fdf7f2 67080 thr->heap->dbg_state_dirty = 1;
7c673cae
FG
67081 process_messages = 1;
67082 }
67083 }
67084
67085 /*
11fdf7f2
TL
67086 * Process messages and send status if necessary.
67087 *
67088 * If we're paused, we'll block for new messages. If we're not
67089 * paused, we'll process anything we can peek but won't block
67090 * for more. Detach (and re-attach) handling is all localized
67091 * to duk_debug_process_messages() too.
67092 *
67093 * Debugger writes outside the message loop may cause debugger
67094 * detach1 phase to run, after which dbg_read_cb == NULL and
67095 * dbg_detaching != 0. The message loop will finish the detach
67096 * by running detach2 phase, so enter the message loop also when
67097 * detaching.
7c673cae
FG
67098 */
67099
67100 act = NULL; /* may be changed */
7c673cae 67101 if (process_messages) {
11fdf7f2 67102 DUK_ASSERT(thr->heap->dbg_processing == 0);
7c673cae 67103 processed_messages = duk_debug_process_messages(thr, 0 /*no_block*/);
11fdf7f2 67104 DUK_ASSERT(thr->heap->dbg_processing == 0);
7c673cae
FG
67105 }
67106
7c673cae
FG
67107 /* Continue checked execution if there are breakpoints or we're stepping.
67108 * Also use checked execution if paused flag is active - it shouldn't be
67109 * because the debug message loop shouldn't terminate if it was. Step out
67110 * is handled by callstack unwind and doesn't need checked execution.
67111 * Note that debugger may have detached due to error or explicit request
67112 * above, so we must recheck attach status.
67113 */
67114
67115 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
67116 act = thr->callstack + thr->callstack_top - 1; /* relookup, may have changed */
67117 if (act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE ||
67118 ((thr->heap->dbg_step_type == DUK_STEP_TYPE_INTO ||
67119 thr->heap->dbg_step_type == DUK_STEP_TYPE_OVER) &&
67120 thr->heap->dbg_step_thread == thr &&
67121 thr->heap->dbg_step_csindex == thr->callstack_top - 1) ||
67122 thr->heap->dbg_paused) {
67123 *out_immediate = 1;
67124 }
67125
67126 /* If we processed any debug messages breakpoints may have
67127 * changed; restart execution to re-check active breakpoints.
67128 */
67129 if (processed_messages) {
67130 DUK_D(DUK_DPRINT("processed debug messages, restart execution to recheck possibly changed breakpoints"));
67131 *out_interrupt_retval = DUK__INT_RESTART;
67132 }
67133 } else {
67134 DUK_D(DUK_DPRINT("debugger became detached, resume normal execution"));
67135 }
67136}
67137#endif /* DUK_USE_DEBUGGER_SUPPORT */
67138
67139DUK_LOCAL duk_small_uint_t duk__executor_interrupt(duk_hthread *thr) {
67140 duk_int_t ctr;
67141 duk_activation *act;
67142 duk_hcompiledfunction *fun;
67143 duk_bool_t immediate = 0;
67144 duk_small_uint_t retval;
67145
67146 DUK_ASSERT(thr != NULL);
67147 DUK_ASSERT(thr->heap != NULL);
67148 DUK_ASSERT(thr->callstack != NULL);
67149 DUK_ASSERT(thr->callstack_top > 0);
67150
67151#if defined(DUK_USE_DEBUG)
67152 thr->heap->inst_count_interrupt += thr->interrupt_init;
67153 DUK_DD(DUK_DDPRINT("execution interrupt, counter=%ld, init=%ld, "
67154 "instruction counts: executor=%ld, interrupt=%ld",
67155 (long) thr->interrupt_counter, (long) thr->interrupt_init,
67156 (long) thr->heap->inst_count_exec, (long) thr->heap->inst_count_interrupt));
67157#endif
67158
67159 retval = DUK__INT_NOACTION;
67160 ctr = DUK_HTHREAD_INTCTR_DEFAULT;
67161
67162 /*
67163 * Avoid nested calls. Concretely this happens during debugging, e.g.
67164 * when we eval() an expression.
11fdf7f2
TL
67165 *
67166 * Also don't interrupt if we're currently doing debug processing
67167 * (which can be initiated outside the bytecode executor) as this
67168 * may cause the debugger to be called recursively. Check required
67169 * for correct operation of throw intercept and other "exotic" halting
67170 * scenarios.
7c673cae
FG
67171 */
67172
11fdf7f2
TL
67173#if defined(DUK_USE_DEBUGGER_SUPPORT)
67174 if (DUK_HEAP_HAS_INTERRUPT_RUNNING(thr->heap) || thr->heap->dbg_processing) {
67175#else
7c673cae 67176 if (DUK_HEAP_HAS_INTERRUPT_RUNNING(thr->heap)) {
11fdf7f2 67177#endif
7c673cae
FG
67178 DUK_DD(DUK_DDPRINT("nested executor interrupt, ignoring"));
67179
67180 /* Set a high interrupt counter; the original executor
67181 * interrupt invocation will rewrite before exiting.
67182 */
67183 thr->interrupt_init = ctr;
67184 thr->interrupt_counter = ctr - 1;
67185 return DUK__INT_NOACTION;
67186 }
67187 DUK_HEAP_SET_INTERRUPT_RUNNING(thr->heap);
67188
67189 act = thr->callstack + thr->callstack_top - 1;
11fdf7f2 67190
7c673cae
FG
67191 fun = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
67192 DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION((duk_hobject *) fun));
11fdf7f2 67193
7c673cae
FG
67194 DUK_UNREF(fun);
67195
67196#if defined(DUK_USE_EXEC_TIMEOUT_CHECK)
67197 /*
67198 * Execution timeout check
67199 */
67200
67201 if (DUK_USE_EXEC_TIMEOUT_CHECK(thr->heap->heap_udata)) {
67202 /* Keep throwing an error whenever we get here. The unusual values
67203 * are set this way because no instruction is ever executed, we just
67204 * throw an error until all try/catch/finally and other catchpoints
67205 * have been exhausted. Duktape/C code gets control at each protected
67206 * call but whenever it enters back into Duktape the RangeError gets
67207 * raised. User exec timeout check must consistently indicate a timeout
67208 * until we've fully bubbled out of Duktape.
67209 */
67210 DUK_D(DUK_DPRINT("execution timeout, throwing a RangeError"));
67211 thr->interrupt_init = 0;
67212 thr->interrupt_counter = 0;
67213 DUK_HEAP_CLEAR_INTERRUPT_RUNNING(thr->heap);
11fdf7f2 67214 DUK_ERROR_RANGE(thr, "execution timeout");
7c673cae
FG
67215 }
67216#endif /* DUK_USE_EXEC_TIMEOUT_CHECK */
67217
67218#if defined(DUK_USE_DEBUGGER_SUPPORT)
11fdf7f2
TL
67219 if (!thr->heap->dbg_processing &&
67220 (thr->heap->dbg_read_cb != NULL || thr->heap->dbg_detaching)) {
67221 /* Avoid recursive re-entry; enter when we're attached or
67222 * detaching (to finish off the pending detach).
67223 */
7c673cae
FG
67224 duk__interrupt_handle_debugger(thr, &immediate, &retval);
67225 act = thr->callstack + thr->callstack_top - 1; /* relookup if changed */
11fdf7f2 67226 DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */
7c673cae
FG
67227 }
67228#endif /* DUK_USE_DEBUGGER_SUPPORT */
67229
67230 /*
67231 * Update the interrupt counter
67232 */
67233
67234 if (immediate) {
67235 /* Cause an interrupt after executing one instruction. */
67236 ctr = 1;
67237 }
67238
67239 /* The counter value is one less than the init value: init value should
67240 * indicate how many instructions are executed before interrupt. To
67241 * execute 1 instruction (after interrupt handler return), counter must
67242 * be 0.
67243 */
11fdf7f2 67244 DUK_ASSERT(ctr >= 1);
7c673cae
FG
67245 thr->interrupt_init = ctr;
67246 thr->interrupt_counter = ctr - 1;
67247 DUK_HEAP_CLEAR_INTERRUPT_RUNNING(thr->heap);
67248
67249 return retval;
67250}
67251#endif /* DUK_USE_INTERRUPT_COUNTER */
67252
67253/*
67254 * Debugger handling for executor restart
67255 *
67256 * Check for breakpoints, stepping, etc, and figure out if we should execute
67257 * in checked or normal mode. Note that we can't do this when an activation
67258 * is created, because breakpoint status (and stepping status) may change
67259 * later, so we must recheck every time we're executing an activation.
11fdf7f2 67260 * This primitive should be side effect free to avoid changes during check.
7c673cae
FG
67261 */
67262
67263#if defined(DUK_USE_DEBUGGER_SUPPORT)
11fdf7f2 67264DUK_LOCAL void duk__executor_recheck_debugger(duk_hthread *thr, duk_activation *act, duk_hcompiledfunction *fun) {
7c673cae
FG
67265 duk_heap *heap;
67266 duk_tval *tv_tmp;
67267 duk_hstring *filename;
67268 duk_small_uint_t bp_idx;
67269 duk_breakpoint **bp_active;
67270
67271 DUK_ASSERT(thr != NULL);
67272 DUK_ASSERT(act != NULL);
67273 DUK_ASSERT(fun != NULL);
67274
67275 heap = thr->heap;
67276 bp_active = heap->dbg_breakpoints_active;
67277 act->flags &= ~DUK_ACT_FLAG_BREAKPOINT_ACTIVE;
67278
67279 tv_tmp = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) fun, DUK_HTHREAD_STRING_FILE_NAME(thr));
67280 if (tv_tmp && DUK_TVAL_IS_STRING(tv_tmp)) {
67281 filename = DUK_TVAL_GET_STRING(tv_tmp);
67282
67283 /* Figure out all active breakpoints. A breakpoint is
67284 * considered active if the current function's fileName
67285 * matches the breakpoint's fileName, AND there is no
67286 * inner function that has matching line numbers
67287 * (otherwise a breakpoint would be triggered both
67288 * inside and outside of the inner function which would
67289 * be confusing). Example:
67290 *
67291 * function foo() {
67292 * print('foo');
67293 * function bar() { <-. breakpoints in these
67294 * print('bar'); | lines should not affect
67295 * } <-' foo() execution
67296 * bar();
67297 * }
67298 *
67299 * We need a few things that are only available when
67300 * debugger support is enabled: (1) a line range for
67301 * each function, and (2) access to the function
67302 * template to access the inner functions (and their
67303 * line ranges).
67304 *
67305 * It's important to have a narrow match for active
67306 * breakpoints so that we don't enter checked execution
67307 * when that's not necessary. For instance, if we're
67308 * running inside a certain function and there's
67309 * breakpoint outside in (after the call site), we
67310 * don't want to slow down execution of the function.
67311 */
67312
67313 for (bp_idx = 0; bp_idx < heap->dbg_breakpoint_count; bp_idx++) {
67314 duk_breakpoint *bp = heap->dbg_breakpoints + bp_idx;
67315 duk_hobject **funcs, **funcs_end;
67316 duk_hcompiledfunction *inner_fun;
67317 duk_bool_t bp_match;
67318
67319 if (bp->filename == filename &&
67320 bp->line >= fun->start_line && bp->line <= fun->end_line) {
67321 bp_match = 1;
67322 DUK_DD(DUK_DDPRINT("breakpoint filename and line match: "
67323 "%s:%ld vs. %s (line %ld vs. %ld-%ld)",
67324 DUK_HSTRING_GET_DATA(bp->filename),
67325 (long) bp->line,
67326 DUK_HSTRING_GET_DATA(filename),
67327 (long) bp->line,
67328 (long) fun->start_line,
67329 (long) fun->end_line));
67330
67331 funcs = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, fun);
67332 funcs_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, fun);
67333 while (funcs != funcs_end) {
67334 inner_fun = (duk_hcompiledfunction *) *funcs;
67335 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) inner_fun));
67336 if (bp->line >= inner_fun->start_line && bp->line <= inner_fun->end_line) {
67337 DUK_DD(DUK_DDPRINT("inner function masks ('captures') breakpoint"));
67338 bp_match = 0;
67339 break;
67340 }
67341 funcs++;
67342 }
67343
67344 if (bp_match) {
67345 /* No need to check for size of bp_active list,
67346 * it's always larger than maximum number of
67347 * breakpoints.
67348 */
67349 act->flags |= DUK_ACT_FLAG_BREAKPOINT_ACTIVE;
67350 *bp_active = heap->dbg_breakpoints + bp_idx;
67351 bp_active++;
67352 }
67353 }
67354 }
67355 }
67356
67357 *bp_active = NULL; /* terminate */
67358
67359 DUK_DD(DUK_DDPRINT("ACTIVE BREAKPOINTS: %ld", (long) (bp_active - thr->heap->dbg_breakpoints_active)));
67360
67361 /* Force pause if we were doing "step into" in another activation. */
67362 if (thr->heap->dbg_step_thread != NULL &&
67363 thr->heap->dbg_step_type == DUK_STEP_TYPE_INTO &&
67364 (thr->heap->dbg_step_thread != thr ||
67365 thr->heap->dbg_step_csindex != thr->callstack_top - 1)) {
67366 DUK_D(DUK_DPRINT("STEP INTO ACTIVE, FORCE PAUSED"));
67367 DUK_HEAP_SET_PAUSED(thr->heap);
67368 }
67369
67370 /* Force interrupt right away if we're paused or in "checked mode".
67371 * Step out is handled by callstack unwind.
67372 */
67373 if (act->flags & (DUK_ACT_FLAG_BREAKPOINT_ACTIVE) ||
67374 thr->heap->dbg_paused ||
67375 (thr->heap->dbg_step_type != DUK_STEP_TYPE_OUT &&
67376 thr->heap->dbg_step_csindex == thr->callstack_top - 1)) {
67377 /* We'll need to interrupt early so recompute the init
67378 * counter to reflect the number of bytecode instructions
67379 * executed so that step counts for e.g. debugger rate
67380 * limiting are accurate.
67381 */
67382 DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init);
67383 thr->interrupt_init = thr->interrupt_init - thr->interrupt_counter;
67384 thr->interrupt_counter = 0;
67385 }
67386}
67387#endif /* DUK_USE_DEBUGGER_SUPPORT */
67388
67389/*
67390 * Ecmascript bytecode executor.
67391 *
67392 * Resume execution for the current thread from its current activation.
67393 * Returns when execution would return from the entry level activation,
67394 * leaving a single return value on top of the stack. Function calls
67395 * and thread resumptions are handled internally. If an error occurs,
67396 * a longjmp() with type DUK_LJ_TYPE_THROW is called on the entry level
67397 * setjmp() jmpbuf.
67398 *
67399 * Ecmascript function calls and coroutine resumptions are handled
11fdf7f2
TL
67400 * internally (by the outer executor function) without recursive C calls.
67401 * Other function calls are handled using duk_handle_call(), increasing
67402 * C recursion depth.
7c673cae 67403 *
11fdf7f2
TL
67404 * Abrupt completions (= long control tranfers) are handled either
67405 * directly by reconfiguring relevant stacks and restarting execution,
67406 * or via a longjmp. Longjmp-free handling is preferable for performance
67407 * (especially Emscripten performance), and is used for: break, continue,
67408 * and return.
7c673cae
FG
67409 *
67410 * For more detailed notes, see doc/execution.rst.
67411 *
67412 * Also see doc/code-issues.rst for discussion of setjmp(), longjmp(),
67413 * and volatile.
67414 */
67415
11fdf7f2
TL
67416/* Presence of 'fun' is config based, there's a marginal performance
67417 * difference and the best option is architecture dependent.
67418 */
67419#if defined(DUK_USE_EXEC_FUN_LOCAL)
67420#define DUK__FUN() fun
67421#else
67422#define DUK__FUN() ((duk_hcompiledfunction *) DUK_ACT_GET_FUNC((thr)->callstack + (thr)->callstack_top - 1))
67423#endif
67424#define DUK__STRICT() (DUK_HOBJECT_HAS_STRICT((duk_hobject *) DUK__FUN()))
67425
67426/* Reg/const access macros: these are very footprint and performance sensitive
67427 * so modify with care.
67428 */
7c673cae
FG
67429#define DUK__REG(x) (*(thr->valstack_bottom + (x)))
67430#define DUK__REGP(x) (thr->valstack_bottom + (x))
67431#define DUK__CONST(x) (*(consts + (x)))
67432#define DUK__CONSTP(x) (consts + (x))
11fdf7f2 67433#if 0
7c673cae
FG
67434#define DUK__REGCONST(x) ((x) < DUK_BC_REGLIMIT ? DUK__REG((x)) : DUK__CONST((x) - DUK_BC_REGLIMIT))
67435#define DUK__REGCONSTP(x) ((x) < DUK_BC_REGLIMIT ? DUK__REGP((x)) : DUK__CONSTP((x) - DUK_BC_REGLIMIT))
11fdf7f2
TL
67436#define DUK__REGCONST(x) *((((x) < DUK_BC_REGLIMIT ? thr->valstack_bottom : consts2) + (x)))
67437#define DUK__REGCONSTP(x) (((x) < DUK_BC_REGLIMIT ? thr->valstack_bottom : consts2) + (x))
67438#endif
67439/* This macro works when a regconst field is 9 bits, [0,0x1ff]. Adding
67440 * DUK_LIKELY/DUK_UNLIKELY increases code footprint and doesn't seem to
67441 * improve performance on x64 (and actually harms performance in some tests).
67442 */
67443#define DUK__RCISREG(x) (((x) & 0x100) == 0)
67444#define DUK__REGCONST(x) (*((DUK__RCISREG((x)) ? thr->valstack_bottom : consts2) + (x)))
67445#define DUK__REGCONSTP(x) ((DUK__RCISREG((x)) ? thr->valstack_bottom : consts2) + (x))
7c673cae
FG
67446
67447#ifdef DUK_USE_VERBOSE_EXECUTOR_ERRORS
67448#define DUK__INTERNAL_ERROR(msg) do { \
11fdf7f2 67449 DUK_ERROR_INTERNAL(thr, (msg)); \
7c673cae
FG
67450 } while (0)
67451#else
67452#define DUK__INTERNAL_ERROR(msg) do { \
67453 goto internal_error; \
67454 } while (0)
67455#endif
67456
67457#define DUK__SYNC_CURR_PC() do { \
67458 duk_activation *act; \
67459 act = thr->callstack + thr->callstack_top - 1; \
67460 act->curr_pc = curr_pc; \
67461 } while (0)
67462#define DUK__SYNC_AND_NULL_CURR_PC() do { \
67463 duk_activation *act; \
67464 act = thr->callstack + thr->callstack_top - 1; \
67465 act->curr_pc = curr_pc; \
67466 thr->ptr_curr_pc = NULL; \
67467 } while (0)
67468
11fdf7f2
TL
67469DUK_LOCAL void duk__handle_executor_error(duk_heap *heap,
67470 duk_hthread *entry_thread,
67471 duk_size_t entry_callstack_top,
67472 duk_int_t entry_call_recursion_depth,
67473 duk_jmpbuf *entry_jmpbuf_ptr) {
67474 duk_small_uint_t lj_ret;
7c673cae 67475
11fdf7f2
TL
67476 /* Longjmp callers are required to sync-and-null thr->ptr_curr_pc
67477 * before longjmp.
7c673cae 67478 */
11fdf7f2
TL
67479 DUK_ASSERT(heap->curr_thread != NULL);
67480 DUK_ASSERT(heap->curr_thread->ptr_curr_pc == NULL);
7c673cae 67481
11fdf7f2 67482 /* XXX: signalling the need to shrink check (only if unwound) */
7c673cae 67483
11fdf7f2
TL
67484 /* Must be restored here to handle e.g. yields properly. */
67485 heap->call_recursion_depth = entry_call_recursion_depth;
7c673cae 67486
11fdf7f2
TL
67487 /* Switch to caller's setjmp() catcher so that if an error occurs
67488 * during error handling, it is always propagated outwards instead
67489 * of causing an infinite loop in our own handler.
67490 */
67491 heap->lj.jmpbuf_ptr = (duk_jmpbuf *) entry_jmpbuf_ptr;
7c673cae 67492
11fdf7f2 67493 lj_ret = duk__handle_longjmp(heap->curr_thread, entry_thread, entry_callstack_top);
7c673cae 67494
11fdf7f2
TL
67495 if (lj_ret == DUK__LONGJMP_RESTART) {
67496 /* Restart bytecode execution, possibly with a changed thread. */
67497 ;
67498 } else {
67499 /* Rethrow error to calling state. */
67500 DUK_ASSERT(lj_ret == DUK__LONGJMP_RETHROW);
7c673cae 67501
11fdf7f2
TL
67502 /* Longjmp handling has restored jmpbuf_ptr. */
67503 DUK_ASSERT(heap->lj.jmpbuf_ptr == entry_jmpbuf_ptr);
7c673cae 67504
11fdf7f2
TL
67505 /* Thread may have changed, e.g. YIELD converted to THROW. */
67506 duk_err_longjmp(heap->curr_thread);
67507 DUK_UNREACHABLE();
67508 }
67509}
67510
67511/* Outer executor with setjmp/longjmp handling. */
67512DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
67513 /* Entry level info. */
67514 duk_hthread *entry_thread;
67515 duk_size_t entry_callstack_top;
67516 duk_int_t entry_call_recursion_depth;
67517 duk_jmpbuf *entry_jmpbuf_ptr;
67518 duk_jmpbuf our_jmpbuf;
67519 duk_heap *heap;
7c673cae
FG
67520
67521 DUK_ASSERT(exec_thr != NULL);
67522 DUK_ASSERT(exec_thr->heap != NULL);
67523 DUK_ASSERT(exec_thr->heap->curr_thread != NULL);
67524 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR((duk_heaphdr *) exec_thr);
67525 DUK_ASSERT(exec_thr->callstack_top >= 1); /* at least one activation, ours */
67526 DUK_ASSERT(DUK_ACT_GET_FUNC(exec_thr->callstack + exec_thr->callstack_top - 1) != NULL);
67527 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(exec_thr->callstack + exec_thr->callstack_top - 1)));
67528
11fdf7f2
TL
67529 entry_thread = exec_thr;
67530 heap = entry_thread->heap;
67531 entry_callstack_top = entry_thread->callstack_top;
67532 entry_call_recursion_depth = entry_thread->heap->call_recursion_depth;
67533 entry_jmpbuf_ptr = entry_thread->heap->lj.jmpbuf_ptr;
7c673cae
FG
67534
67535 /*
7c673cae
FG
67536 * Note: we currently assume that the setjmp() catchpoint is
67537 * not re-entrant (longjmp() cannot be called more than once
67538 * for a single setjmp()).
11fdf7f2
TL
67539 *
67540 * See doc/code-issues.rst for notes on variable assignment
67541 * before and after setjmp().
7c673cae
FG
67542 */
67543
11fdf7f2
TL
67544 for (;;) {
67545 heap->lj.jmpbuf_ptr = &our_jmpbuf;
67546 DUK_ASSERT(heap->lj.jmpbuf_ptr != NULL);
7c673cae 67547
11fdf7f2
TL
67548#if defined(DUK_USE_CPP_EXCEPTIONS)
67549 try {
67550#else
67551 DUK_ASSERT(heap->lj.jmpbuf_ptr == &our_jmpbuf);
67552 if (DUK_SETJMP(our_jmpbuf.jb) == 0) {
67553#endif
67554 /* Execute bytecode until returned or longjmp(). */
67555 duk__js_execute_bytecode_inner(entry_thread, entry_callstack_top);
7c673cae 67556
11fdf7f2
TL
67557 /* Successful return: restore jmpbuf and return to caller. */
67558 heap->lj.jmpbuf_ptr = entry_jmpbuf_ptr;
7c673cae 67559
11fdf7f2
TL
67560 return;
67561#if defined(DUK_USE_CPP_EXCEPTIONS)
67562 } catch (duk_internal_exception &exc) {
67563#else
67564 } else {
67565#endif
67566#if defined(DUK_USE_CPP_EXCEPTIONS)
67567 DUK_UNREF(exc);
67568#endif
67569 DUK_DDD(DUK_DDDPRINT("longjmp caught by bytecode executor"));
67570
67571 duk__handle_executor_error(heap,
67572 entry_thread,
67573 entry_callstack_top,
67574 entry_call_recursion_depth,
67575 entry_jmpbuf_ptr);
67576 }
67577#if defined(DUK_USE_CPP_EXCEPTIONS)
67578 catch (std::exception &exc) {
67579 const char *what = exc.what();
67580 if (!what) {
67581 what = "unknown";
67582 }
67583 DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
67584 try {
67585 DUK_ASSERT(heap->curr_thread != NULL);
67586 DUK_ERROR_FMT1(heap->curr_thread, DUK_ERR_API_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
67587 } catch (duk_internal_exception exc) {
67588 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
67589 DUK_UNREF(exc);
67590 duk__handle_executor_error(heap,
67591 entry_thread,
67592 entry_callstack_top,
67593 entry_call_recursion_depth,
67594 entry_jmpbuf_ptr);
67595 }
67596 } catch (...) {
67597 DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
67598 try {
67599 DUK_ASSERT(heap->curr_thread != NULL);
67600 DUK_ERROR_API(heap->curr_thread, "caught invalid c++ exception (perhaps thrown by user code)");
67601 } catch (duk_internal_exception exc) {
67602 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
67603 DUK_UNREF(exc);
67604 duk__handle_executor_error(heap,
67605 entry_thread,
67606 entry_callstack_top,
67607 entry_call_recursion_depth,
67608 entry_jmpbuf_ptr);
67609 }
67610 }
67611#endif
67612 }
7c673cae 67613
11fdf7f2
TL
67614 DUK_UNREACHABLE();
67615}
7c673cae 67616
11fdf7f2
TL
67617/* Inner executor, performance critical. */
67618DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_size_t entry_callstack_top) {
67619 /* Current PC, accessed by other functions through thr->ptr_to_curr_pc.
67620 * Critical for performance. It would be safest to make this volatile,
67621 * but that eliminates performance benefits; aliasing guarantees
67622 * should be enough though.
67623 */
67624 duk_instr_t *curr_pc; /* bytecode has a stable pointer */
7c673cae 67625
11fdf7f2
TL
67626 /* Hot variables for interpretation. Critical for performance,
67627 * but must add sparingly to minimize register shuffling.
67628 */
67629 duk_hthread *thr; /* stable */
67630 duk_tval *consts; /* stable */
67631 duk_tval *consts2; /* stable; precalculated for faster lookups */
67632 duk_uint_fast32_t ins;
67633 /* 'funcs' is quite rarely used, so no local for it */
67634#if defined(DUK_USE_EXEC_FUN_LOCAL)
67635 duk_hcompiledfunction *fun;
67636#else
67637 /* 'fun' is quite rarely used, so no local for it */
67638#endif
7c673cae 67639
11fdf7f2
TL
67640#ifdef DUK_USE_INTERRUPT_COUNTER
67641 duk_int_t int_ctr;
67642#endif
7c673cae 67643
11fdf7f2
TL
67644#ifdef DUK_USE_ASSERTIONS
67645 duk_size_t valstack_top_base; /* valstack top, should match before interpreting each op (no leftovers) */
67646#endif
7c673cae
FG
67647
67648 /*
67649 * Restart execution by reloading thread state.
67650 *
67651 * Note that 'thr' and any thread configuration may have changed,
11fdf7f2 67652 * so all local variables are suspect and we need to reinitialize.
7c673cae
FG
67653 *
67654 * The number of local variables should be kept to a minimum: if
67655 * the variables are spilled, they will need to be loaded from
67656 * memory anyway.
67657 *
67658 * Any 'goto restart_execution;' code path in opcode dispatch must
67659 * ensure 'curr_pc' is synced back to act->curr_pc before the goto
67660 * takes place.
7c673cae
FG
67661 *
67662 * The interpreter must be very careful with memory pointers, as
67663 * many pointers are not guaranteed to be 'stable' and may be
67664 * reallocated and relocated on-the-fly quite easily (e.g. by a
67665 * memory allocation or a property access).
67666 *
67667 * The following are assumed to have stable pointers:
67668 * - the current thread
67669 * - the current function
67670 * - the bytecode, constant table, inner function table of the
67671 * current function (as they are a part of the function allocation)
67672 *
67673 * The following are assumed to have semi-stable pointers:
67674 * - the current activation entry: stable as long as callstack
67675 * is not changed (reallocated by growing or shrinking), or
67676 * by any garbage collection invocation (through finalizers)
67677 * - Note in particular that ANY DECREF can invalidate the
11fdf7f2
TL
67678 * activation pointer, so for the most part a fresh lookup
67679 * is required
7c673cae
FG
67680 *
67681 * The following are not assumed to have stable pointers at all:
67682 * - the value stack (registers) of the current thread
67683 * - the catch stack of the current thread
67684 *
67685 * See execution.rst for discussion.
67686 */
67687
11fdf7f2
TL
67688 restart_execution:
67689
67690 /* Lookup current thread; use the stable 'entry_thread' for this to
67691 * avoid clobber warnings. Any valid, reachable 'thr' value would be
67692 * fine for this, so using 'entry_thread' is just to silence warnings.
67693 */
67694 thr = entry_thread->heap->curr_thread;
7c673cae 67695 DUK_ASSERT(thr != NULL);
11fdf7f2
TL
67696 DUK_ASSERT(thr->callstack_top >= 1);
67697 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL);
67698 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)));
67699
67700 thr->ptr_curr_pc = &curr_pc;
67701
67702 /* Relookup and initialize dispatch loop variables. Debugger check. */
67703 {
67704 duk_activation *act;
67705#if !defined(DUK_USE_EXEC_FUN_LOCAL)
67706 duk_hcompiledfunction *fun;
67707#endif
67708
67709 /* Assume interrupt init/counter are properly initialized here. */
67710 /* Assume that thr->valstack_bottom has been set-up before getting here. */
67711
67712 act = thr->callstack + thr->callstack_top - 1;
67713 fun = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
67714 DUK_ASSERT(fun != NULL);
67715 DUK_ASSERT(thr->valstack_top - thr->valstack_bottom == fun->nregs);
67716 consts = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, fun);
67717 DUK_ASSERT(consts != NULL);
67718 consts2 = consts - DUK_BC_REGLIMIT;
67719
67720#if defined(DUK_USE_DEBUGGER_SUPPORT)
67721 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap) && !thr->heap->dbg_processing) {
67722 duk__executor_recheck_debugger(thr, act, fun);
67723 act = thr->callstack + thr->callstack_top - 1; /* relookup after side effects (no side effects currently however) */
67724 }
67725#endif /* DUK_USE_DEBUGGER_SUPPORT */
67726
67727#ifdef DUK_USE_ASSERTIONS
67728 valstack_top_base = (duk_size_t) (thr->valstack_top - thr->valstack);
67729#endif
67730
67731 /* Set up curr_pc for opcode dispatch. */
67732 curr_pc = act->curr_pc;
67733 }
7c673cae
FG
67734
67735 DUK_DD(DUK_DDPRINT("restarting execution, thr %p, act idx %ld, fun %p,"
67736 "consts %p, funcs %p, lev %ld, regbot %ld, regtop %ld, catchstack_top=%ld, "
67737 "preventcount=%ld",
67738 (void *) thr,
67739 (long) (thr->callstack_top - 1),
11fdf7f2
TL
67740 (void *) DUK__FUN(),
67741 (void *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, DUK__FUN()),
67742 (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, DUK__FUN()),
7c673cae
FG
67743 (long) (thr->callstack_top - 1),
67744 (long) (thr->valstack_bottom - thr->valstack),
67745 (long) (thr->valstack_top - thr->valstack),
67746 (long) thr->catchstack_top,
67747 (long) thr->callstack_preventcount));
67748
11fdf7f2 67749 /* Dispatch loop. */
7c673cae
FG
67750
67751 for (;;) {
67752 DUK_ASSERT(thr->callstack_top >= 1);
11fdf7f2 67753 DUK_ASSERT(thr->valstack_top - thr->valstack_bottom == DUK__FUN()->nregs);
7c673cae
FG
67754 DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack) == valstack_top_base);
67755
67756 /* Executor interrupt counter check, used to implement breakpoints,
67757 * debugging interface, execution timeouts, etc. The counter is heap
67758 * specific but is maintained in the current thread to make the check
67759 * as fast as possible. The counter is copied back to the heap struct
67760 * whenever a thread switch occurs by the DUK_HEAP_SWITCH_THREAD() macro.
67761 */
11fdf7f2 67762#if defined(DUK_USE_INTERRUPT_COUNTER)
7c673cae
FG
67763 int_ctr = thr->interrupt_counter;
67764 if (DUK_LIKELY(int_ctr > 0)) {
67765 thr->interrupt_counter = int_ctr - 1;
67766 } else {
67767 /* Trigger at zero or below */
67768 duk_small_uint_t exec_int_ret;
67769
67770 /* Write curr_pc back for the debugger. */
67771 DUK_ASSERT(thr->callstack_top > 0);
67772 {
67773 duk_activation *act;
67774 act = thr->callstack + thr->callstack_top - 1;
67775 act->curr_pc = (duk_instr_t *) curr_pc;
67776 }
67777
67778 /* Force restart caused by a function return; must recheck
67779 * debugger breakpoints before checking line transitions,
67780 * see GH-303. Restart and then handle interrupt_counter
67781 * zero again.
67782 */
67783#if defined(DUK_USE_DEBUGGER_SUPPORT)
67784 if (thr->heap->dbg_force_restart) {
67785 DUK_DD(DUK_DDPRINT("dbg_force_restart flag forced restart execution")); /* GH-303 */
67786 thr->heap->dbg_force_restart = 0;
67787 goto restart_execution;
67788 }
67789#endif
67790
67791 exec_int_ret = duk__executor_interrupt(thr);
67792 if (exec_int_ret == DUK__INT_RESTART) {
67793 /* curr_pc synced back above */
67794 goto restart_execution;
67795 }
67796 }
11fdf7f2 67797#endif /* DUK_USE_INTERRUPT_COUNTER */
7c673cae 67798#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
11fdf7f2
TL
67799 /* For cross-checking during development: ensure dispatch count
67800 * matches cumulative interrupt counter init value sums.
67801 */
7c673cae
FG
67802 thr->heap->inst_count_exec++;
67803#endif
67804
67805#if defined(DUK_USE_ASSERTIONS) || defined(DUK_USE_DEBUG)
67806 {
67807 duk_activation *act;
67808 act = thr->callstack + thr->callstack_top - 1;
11fdf7f2
TL
67809 DUK_ASSERT(curr_pc >= DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, DUK__FUN()));
67810 DUK_ASSERT(curr_pc < DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr->heap, DUK__FUN()));
7c673cae
FG
67811 DUK_UNREF(act); /* if debugging disabled */
67812
67813 DUK_DDD(DUK_DDDPRINT("executing bytecode: pc=%ld, ins=0x%08lx, op=%ld, valstack_top=%ld/%ld, nregs=%ld --> %!I",
11fdf7f2 67814 (long) (curr_pc - DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, DUK__FUN())),
7c673cae
FG
67815 (unsigned long) *curr_pc,
67816 (long) DUK_DEC_OP(*curr_pc),
67817 (long) (thr->valstack_top - thr->valstack),
67818 (long) (thr->valstack_end - thr->valstack),
11fdf7f2 67819 (long) (DUK__FUN() ? DUK__FUN()->nregs : -1),
7c673cae
FG
67820 (duk_instr_t) *curr_pc));
67821 }
67822#endif
67823
67824#if defined(DUK_USE_ASSERTIONS)
11fdf7f2
TL
67825 /* Quite heavy assert: check valstack policy. Improper
67826 * shuffle instructions can write beyond valstack_top/end
67827 * so this check catches them in the act.
7c673cae
FG
67828 */
67829 {
67830 duk_tval *tv;
67831 tv = thr->valstack_top;
67832 while (tv != thr->valstack_end) {
11fdf7f2 67833 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv));
7c673cae
FG
67834 tv++;
67835 }
67836 }
67837#endif
67838
67839 ins = *curr_pc++;
67840
67841 /* Typing: use duk_small_(u)int_fast_t when decoding small
67842 * opcode fields (op, A, B, C) and duk_(u)int_fast_t when
67843 * decoding larger fields (e.g. BC which is 18 bits). Use
67844 * unsigned variant by default, signed when the value is used
67845 * in signed arithmetic. Using variable names such as 'a', 'b',
67846 * 'c', 'bc', etc makes it easier to spot typing mismatches.
67847 */
67848
67849 /* XXX: the best typing needs to be validated by perf measurement:
67850 * e.g. using a small type which is the cast to a larger duk_idx_t
67851 * may be slower than declaring the variable as a duk_idx_t in the
67852 * first place.
67853 */
67854
67855 /* XXX: use macros for the repetitive tval/refcount handling. */
67856
67857 switch ((int) DUK_DEC_OP(ins)) {
67858 /* XXX: switch cast? */
67859
67860 case DUK_OP_LDREG: {
67861 duk_small_uint_fast_t a;
67862 duk_uint_fast_t bc;
7c673cae
FG
67863 duk_tval *tv1, *tv2;
67864
67865 a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
67866 bc = DUK_DEC_BC(ins); tv2 = DUK__REGP(bc);
11fdf7f2 67867 DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv1, tv2); /* side effects */
7c673cae
FG
67868 break;
67869 }
67870
67871 case DUK_OP_STREG: {
67872 duk_small_uint_fast_t a;
67873 duk_uint_fast_t bc;
7c673cae
FG
67874 duk_tval *tv1, *tv2;
67875
67876 a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
67877 bc = DUK_DEC_BC(ins); tv2 = DUK__REGP(bc);
11fdf7f2 67878 DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv2, tv1); /* side effects */
7c673cae
FG
67879 break;
67880 }
67881
67882 case DUK_OP_LDCONST: {
67883 duk_small_uint_fast_t a;
67884 duk_uint_fast_t bc;
7c673cae
FG
67885 duk_tval *tv1, *tv2;
67886
67887 a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
67888 bc = DUK_DEC_BC(ins); tv2 = DUK__CONSTP(bc);
11fdf7f2 67889 DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv1, tv2); /* side effects */
7c673cae
FG
67890 break;
67891 }
67892
67893 case DUK_OP_LDINT: {
67894 duk_small_uint_fast_t a;
67895 duk_int_fast_t bc;
7c673cae
FG
67896 duk_tval *tv1;
67897#if defined(DUK_USE_FASTINT)
67898 duk_int32_t val;
67899#else
67900 duk_double_t val;
67901#endif
67902
67903#if defined(DUK_USE_FASTINT)
67904 a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
67905 bc = DUK_DEC_BC(ins); val = (duk_int32_t) (bc - DUK_BC_LDINT_BIAS);
11fdf7f2 67906 DUK_TVAL_SET_FASTINT_I32_UPDREF(thr, tv1, val); /* side effects */
7c673cae
FG
67907#else
67908 a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
67909 bc = DUK_DEC_BC(ins); val = (duk_double_t) (bc - DUK_BC_LDINT_BIAS);
11fdf7f2 67910 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv1, val); /* side effects */
7c673cae
FG
67911#endif
67912 break;
67913 }
67914
67915 case DUK_OP_LDINTX: {
67916 duk_small_uint_fast_t a;
67917 duk_tval *tv1;
67918 duk_double_t val;
67919
67920 /* LDINTX is not necessarily in FASTINT range, so
67921 * no fast path for now.
67922 *
67923 * XXX: perhaps restrict LDINTX to fastint range, wider
67924 * range very rarely needed.
67925 */
67926
67927 a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
67928 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
67929 val = DUK_TVAL_GET_NUMBER(tv1) * ((duk_double_t) (1L << DUK_BC_LDINTX_SHIFT)) +
67930 (duk_double_t) DUK_DEC_BC(ins);
67931#if defined(DUK_USE_FASTINT)
67932 DUK_TVAL_SET_NUMBER_CHKFAST(tv1, val);
67933#else
67934 DUK_TVAL_SET_NUMBER(tv1, val);
67935#endif
67936 break;
67937 }
67938
67939 case DUK_OP_MPUTOBJ:
67940 case DUK_OP_MPUTOBJI: {
67941 duk_context *ctx = (duk_context *) thr;
67942 duk_small_uint_fast_t a;
67943 duk_tval *tv1;
67944 duk_hobject *obj;
67945 duk_uint_fast_t idx;
67946 duk_small_uint_fast_t count;
67947
67948 /* A -> register of target object
67949 * B -> first register of key/value pair list
67950 * C -> number of key/value pairs
67951 */
67952
67953 a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
67954 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1));
67955 obj = DUK_TVAL_GET_OBJECT(tv1);
67956
67957 idx = (duk_uint_fast_t) DUK_DEC_B(ins);
67958 if (DUK_DEC_OP(ins) == DUK_OP_MPUTOBJI) {
67959 duk_tval *tv_ind = DUK__REGP(idx);
67960 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
67961 idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
67962 }
67963
67964 count = (duk_small_uint_fast_t) DUK_DEC_C(ins);
67965
67966#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
67967 if (DUK_UNLIKELY(idx + count * 2 > (duk_uint_fast_t) duk_get_top(ctx))) {
67968 /* XXX: use duk_is_valid_index() instead? */
67969 /* XXX: improve check; check against nregs, not against top */
67970 DUK__INTERNAL_ERROR("MPUTOBJ out of bounds");
67971 }
67972#endif
67973
67974 duk_push_hobject(ctx, obj);
67975
67976 while (count > 0) {
67977 /* XXX: faster initialization (direct access or better primitives) */
67978
67979 duk_push_tval(ctx, DUK__REGP(idx));
67980 DUK_ASSERT(duk_is_string(ctx, -1));
67981 duk_push_tval(ctx, DUK__REGP(idx + 1)); /* -> [... obj key value] */
67982 duk_xdef_prop_wec(ctx, -3); /* -> [... obj] */
67983
67984 count--;
67985 idx += 2;
67986 }
67987
67988 duk_pop(ctx); /* [... obj] -> [...] */
67989 break;
67990 }
67991
67992 case DUK_OP_MPUTARR:
67993 case DUK_OP_MPUTARRI: {
67994 duk_context *ctx = (duk_context *) thr;
67995 duk_small_uint_fast_t a;
67996 duk_tval *tv1;
67997 duk_hobject *obj;
67998 duk_uint_fast_t idx;
67999 duk_small_uint_fast_t count;
68000 duk_uint32_t arr_idx;
68001
68002 /* A -> register of target object
68003 * B -> first register of value data (start_index, value1, value2, ..., valueN)
68004 * C -> number of key/value pairs (N)
68005 */
68006
68007 a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
68008 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1));
68009 obj = DUK_TVAL_GET_OBJECT(tv1);
68010 DUK_ASSERT(obj != NULL);
68011
68012 idx = (duk_uint_fast_t) DUK_DEC_B(ins);
68013 if (DUK_DEC_OP(ins) == DUK_OP_MPUTARRI) {
68014 duk_tval *tv_ind = DUK__REGP(idx);
68015 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
68016 idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
68017 }
68018
68019 count = (duk_small_uint_fast_t) DUK_DEC_C(ins);
68020
68021#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
68022 if (idx + count + 1 > (duk_uint_fast_t) duk_get_top(ctx)) {
68023 /* XXX: use duk_is_valid_index() instead? */
68024 /* XXX: improve check; check against nregs, not against top */
68025 DUK__INTERNAL_ERROR("MPUTARR out of bounds");
68026 }
68027#endif
68028
68029 tv1 = DUK__REGP(idx);
68030 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
68031 arr_idx = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv1);
68032 idx++;
68033
68034 duk_push_hobject(ctx, obj);
68035
68036 while (count > 0) {
68037 /* duk_xdef_prop() will define an own property without any array
68038 * special behaviors. We'll need to set the array length explicitly
68039 * in the end. For arrays with elisions, the compiler will emit an
68040 * explicit SETALEN which will update the length.
68041 */
68042
68043 /* XXX: because we're dealing with 'own' properties of a fresh array,
68044 * the array initializer should just ensure that the array has a large
68045 * enough array part and write the values directly into array part,
68046 * and finally set 'length' manually in the end (as already happens now).
68047 */
68048
68049 duk_push_tval(ctx, DUK__REGP(idx)); /* -> [... obj value] */
68050 duk_xdef_prop_index_wec(ctx, -2, arr_idx); /* -> [... obj] */
68051
68052 /* XXX: could use at least one fewer loop counters */
68053 count--;
68054 idx++;
68055 arr_idx++;
68056 }
68057
68058 /* XXX: E5.1 Section 11.1.4 coerces the final length through
68059 * ToUint32() which is odd but happens now as a side effect of
68060 * 'arr_idx' type.
68061 */
68062 duk_hobject_set_length(thr, obj, (duk_uint32_t) arr_idx);
68063
68064 duk_pop(ctx); /* [... obj] -> [...] */
68065 break;
68066 }
68067
68068 case DUK_OP_NEW:
68069 case DUK_OP_NEWI: {
68070 duk_context *ctx = (duk_context *) thr;
68071 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68072 duk_uint_fast_t idx;
68073 duk_small_uint_fast_t i;
68074
68075 /* A -> unused (reserved for flags, for consistency with DUK_OP_CALL)
68076 * B -> target register and start reg: constructor, arg1, ..., argN
68077 * (for DUK_OP_NEWI, 'b' is indirect)
68078 * C -> num args (N)
68079 */
68080
68081 /* duk_new() will call the constuctor using duk_handle_call().
68082 * A constructor call prevents a yield from inside the constructor,
68083 * even if the constructor is an Ecmascript function.
68084 */
68085
68086 /* Don't need to sync curr_pc here; duk_new() will do that
68087 * when it augments the created error.
68088 */
68089
68090 /* XXX: unnecessary copying of values? Just set 'top' to
68091 * b + c, and let the return handling fix up the stack frame?
68092 */
68093
68094 idx = (duk_uint_fast_t) DUK_DEC_B(ins);
68095 if (DUK_DEC_OP(ins) == DUK_OP_NEWI) {
68096 duk_tval *tv_ind = DUK__REGP(idx);
68097 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
68098 idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
68099 }
68100
68101#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
68102 if (idx + c + 1 > (duk_uint_fast_t) duk_get_top(ctx)) {
68103 /* XXX: use duk_is_valid_index() instead? */
68104 /* XXX: improve check; check against nregs, not against top */
68105 DUK__INTERNAL_ERROR("NEW out of bounds");
68106 }
68107#endif
68108
68109 duk_require_stack(ctx, (duk_idx_t) c);
68110 duk_push_tval(ctx, DUK__REGP(idx));
68111 for (i = 0; i < c; i++) {
68112 duk_push_tval(ctx, DUK__REGP(idx + i + 1));
68113 }
68114 duk_new(ctx, (duk_idx_t) c); /* [... constructor arg1 ... argN] -> [retval] */
68115 DUK_DDD(DUK_DDDPRINT("NEW -> %!iT", (duk_tval *) duk_get_tval(ctx, -1)));
68116 duk_replace(ctx, (duk_idx_t) idx);
68117
68118 /* When debugger is enabled, we need to recheck the activation
68119 * status after returning. This is now handled by call handling
68120 * and heap->dbg_force_restart.
68121 */
68122 break;
68123 }
68124
68125 case DUK_OP_REGEXP: {
68126#ifdef DUK_USE_REGEXP_SUPPORT
68127 duk_context *ctx = (duk_context *) thr;
68128 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68129 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68130 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68131
68132 /* A -> target register
68133 * B -> bytecode (also contains flags)
68134 * C -> escaped source
68135 */
68136
68137 duk_push_tval(ctx, DUK__REGCONSTP(c));
68138 duk_push_tval(ctx, DUK__REGCONSTP(b)); /* -> [ ... escaped_source bytecode ] */
68139 duk_regexp_create_instance(thr); /* -> [ ... regexp_instance ] */
68140 DUK_DDD(DUK_DDDPRINT("regexp instance: %!iT", (duk_tval *) duk_get_tval(ctx, -1)));
68141 duk_replace(ctx, (duk_idx_t) a);
68142#else
68143 /* The compiler should never emit DUK_OP_REGEXP if there is no
68144 * regexp support.
68145 */
68146 DUK__INTERNAL_ERROR("no regexp support");
68147#endif
68148
68149 break;
68150 }
68151
68152 case DUK_OP_CSREG:
68153 case DUK_OP_CSREGI: {
68154 /*
68155 * Assuming a register binds to a variable declared within this
68156 * function (a declarative binding), the 'this' for the call
68157 * setup is always 'undefined'. E5 Section 10.2.1.1.6.
68158 */
68159
68160 duk_context *ctx = (duk_context *) thr;
68161 duk_small_uint_fast_t b = DUK_DEC_B(ins); /* restricted to regs */
68162 duk_uint_fast_t idx;
68163
68164 /* A -> target register (A, A+1) for call setup
68165 * (for DUK_OP_CSREGI, 'a' is indirect)
68166 * B -> register containing target function (not type checked here)
68167 */
68168
68169 /* XXX: direct manipulation, or duk_replace_tval() */
68170
68171 /* Note: target registers a and a+1 may overlap with DUK__REGP(b).
68172 * Careful here.
68173 */
68174
68175 idx = (duk_uint_fast_t) DUK_DEC_A(ins);
68176 if (DUK_DEC_OP(ins) == DUK_OP_CSREGI) {
68177 duk_tval *tv_ind = DUK__REGP(idx);
68178 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
68179 idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
68180 }
68181
68182#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
68183 if (idx + 2 > (duk_uint_fast_t) duk_get_top(ctx)) {
68184 /* XXX: use duk_is_valid_index() instead? */
68185 /* XXX: improve check; check against nregs, not against top */
68186 DUK__INTERNAL_ERROR("CSREG out of bounds");
68187 }
68188#endif
68189
68190 duk_push_tval(ctx, DUK__REGP(b));
68191 duk_replace(ctx, (duk_idx_t) idx);
68192 duk_push_undefined(ctx);
68193 duk_replace(ctx, (duk_idx_t) (idx + 1));
68194 break;
68195 }
68196
68197 case DUK_OP_GETVAR: {
68198 duk_context *ctx = (duk_context *) thr;
68199 duk_activation *act;
68200 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68201 duk_uint_fast_t bc = DUK_DEC_BC(ins);
68202 duk_tval *tv1;
68203 duk_hstring *name;
68204
68205 tv1 = DUK__CONSTP(bc);
68206 DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
68207 name = DUK_TVAL_GET_STRING(tv1);
68208 DUK_ASSERT(name != NULL);
68209 DUK_DDD(DUK_DDDPRINT("GETVAR: '%!O'", (duk_heaphdr *) name));
68210 act = thr->callstack + thr->callstack_top - 1;
68211 (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */
68212
68213 duk_pop(ctx); /* 'this' binding is not needed here */
68214 duk_replace(ctx, (duk_idx_t) a);
68215 break;
68216 }
68217
68218 case DUK_OP_PUTVAR: {
68219 duk_activation *act;
68220 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68221 duk_uint_fast_t bc = DUK_DEC_BC(ins);
68222 duk_tval *tv1;
68223 duk_hstring *name;
68224
68225 tv1 = DUK__CONSTP(bc);
68226 DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
68227 name = DUK_TVAL_GET_STRING(tv1);
68228 DUK_ASSERT(name != NULL);
68229
68230 /* XXX: putvar takes a duk_tval pointer, which is awkward and
68231 * should be reworked.
68232 */
68233
68234 tv1 = DUK__REGP(a); /* val */
68235 act = thr->callstack + thr->callstack_top - 1;
68236 duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT());
68237 break;
68238 }
68239
68240 case DUK_OP_DECLVAR: {
68241 duk_activation *act;
68242 duk_context *ctx = (duk_context *) thr;
68243 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68244 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68245 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68246 duk_tval *tv1;
68247 duk_hstring *name;
68248 duk_small_uint_t prop_flags;
68249 duk_bool_t is_func_decl;
68250 duk_bool_t is_undef_value;
68251
68252 tv1 = DUK__REGCONSTP(b);
68253 DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
68254 name = DUK_TVAL_GET_STRING(tv1);
68255 DUK_ASSERT(name != NULL);
68256
68257 is_undef_value = ((a & DUK_BC_DECLVAR_FLAG_UNDEF_VALUE) != 0);
68258 is_func_decl = ((a & DUK_BC_DECLVAR_FLAG_FUNC_DECL) != 0);
68259
68260 /* XXX: declvar takes an duk_tval pointer, which is awkward and
68261 * should be reworked.
68262 */
68263
68264 /* Compiler is responsible for selecting property flags (configurability,
68265 * writability, etc).
68266 */
68267 prop_flags = a & DUK_PROPDESC_FLAGS_MASK;
68268
68269 if (is_undef_value) {
68270 duk_push_undefined(ctx);
68271 } else {
68272 duk_push_tval(ctx, DUK__REGCONSTP(c));
68273 }
11fdf7f2 68274 tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1);
7c673cae
FG
68275
68276 act = thr->callstack + thr->callstack_top - 1;
68277 if (duk_js_declvar_activation(thr, act, name, tv1, prop_flags, is_func_decl)) {
11fdf7f2
TL
68278 if (is_undef_value) {
68279 /* Already declared but no initializer value
68280 * (e.g. 'var xyz;'), no-op.
68281 */
68282 } else {
68283 /* Already declared, update value. */
68284 tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1);
68285 duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT());
68286 }
7c673cae
FG
68287 }
68288
68289 duk_pop(ctx);
68290 break;
68291 }
68292
68293 case DUK_OP_DELVAR: {
68294 duk_activation *act;
68295 duk_context *ctx = (duk_context *) thr;
68296 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68297 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68298 duk_tval *tv1;
68299 duk_hstring *name;
68300 duk_bool_t rc;
68301
68302 tv1 = DUK__REGCONSTP(b);
68303 DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
68304 name = DUK_TVAL_GET_STRING(tv1);
68305 DUK_ASSERT(name != NULL);
68306 DUK_DDD(DUK_DDDPRINT("DELVAR '%!O'", (duk_heaphdr *) name));
68307 act = thr->callstack + thr->callstack_top - 1;
68308 rc = duk_js_delvar_activation(thr, act, name);
68309
68310 duk_push_boolean(ctx, rc);
68311 duk_replace(ctx, (duk_idx_t) a);
68312 break;
68313 }
68314
68315 case DUK_OP_CSVAR:
68316 case DUK_OP_CSVARI: {
68317 /* 'this' value:
68318 * E5 Section 6.b.i
68319 *
68320 * The only (standard) case where the 'this' binding is non-null is when
68321 * (1) the variable is found in an object environment record, and
68322 * (2) that object environment record is a 'with' block.
68323 *
68324 */
68325
68326 duk_context *ctx = (duk_context *) thr;
68327 duk_activation *act;
68328 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68329 duk_uint_fast_t idx;
68330 duk_tval *tv1;
68331 duk_hstring *name;
68332
68333 tv1 = DUK__REGCONSTP(b);
68334 DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
68335 name = DUK_TVAL_GET_STRING(tv1);
68336 DUK_ASSERT(name != NULL);
68337 act = thr->callstack + thr->callstack_top - 1;
68338 (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */
68339
68340 /* Note: target registers a and a+1 may overlap with DUK__REGCONSTP(b)
68341 * and DUK__REGCONSTP(c). Careful here.
68342 */
68343
68344 idx = (duk_uint_fast_t) DUK_DEC_A(ins);
68345 if (DUK_DEC_OP(ins) == DUK_OP_CSVARI) {
68346 duk_tval *tv_ind = DUK__REGP(idx);
68347 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
68348 idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
68349 }
68350
68351#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
68352 if (idx + 2 > (duk_uint_fast_t) duk_get_top(ctx)) {
68353 /* XXX: use duk_is_valid_index() instead? */
68354 /* XXX: improve check; check against nregs, not against top */
68355 DUK__INTERNAL_ERROR("CSVAR out of bounds");
68356 }
68357#endif
68358
68359 duk_replace(ctx, (duk_idx_t) (idx + 1)); /* 'this' binding */
68360 duk_replace(ctx, (duk_idx_t) idx); /* variable value (function, we hope, not checked here) */
68361 break;
68362 }
68363
68364 case DUK_OP_CLOSURE: {
68365 duk_context *ctx = (duk_context *) thr;
68366 duk_activation *act;
11fdf7f2 68367 duk_hcompiledfunction *fun;
7c673cae
FG
68368 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68369 duk_uint_fast_t bc = DUK_DEC_BC(ins);
68370 duk_hobject *fun_temp;
68371
68372 /* A -> target reg
68373 * BC -> inner function index
68374 */
68375
68376 DUK_DDD(DUK_DDDPRINT("CLOSURE to target register %ld, fnum %ld (count %ld)",
11fdf7f2 68377 (long) a, (long) bc, (long) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(thr->heap, DUK__FUN())));
7c673cae
FG
68378
68379 DUK_ASSERT_DISABLE(bc >= 0); /* unsigned */
11fdf7f2
TL
68380 DUK_ASSERT((duk_uint_t) bc < (duk_uint_t) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(thr->heap, DUK__FUN()));
68381
68382 act = thr->callstack + thr->callstack_top - 1;
68383 fun = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
7c673cae
FG
68384 fun_temp = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, fun)[bc];
68385 DUK_ASSERT(fun_temp != NULL);
68386 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(fun_temp));
68387
68388 DUK_DDD(DUK_DDDPRINT("CLOSURE: function template is: %p -> %!O",
68389 (void *) fun_temp, (duk_heaphdr *) fun_temp));
68390
7c673cae
FG
68391 if (act->lex_env == NULL) {
68392 DUK_ASSERT(act->var_env == NULL);
68393 duk_js_init_activation_environment_records_delayed(thr, act);
11fdf7f2 68394 act = thr->callstack + thr->callstack_top - 1;
7c673cae
FG
68395 }
68396 DUK_ASSERT(act->lex_env != NULL);
68397 DUK_ASSERT(act->var_env != NULL);
68398
68399 /* functions always have a NEWENV flag, i.e. they get a
68400 * new variable declaration environment, so only lex_env
68401 * matters here.
68402 */
68403 duk_js_push_closure(thr,
68404 (duk_hcompiledfunction *) fun_temp,
68405 act->var_env,
11fdf7f2
TL
68406 act->lex_env,
68407 1 /*add_auto_proto*/);
7c673cae
FG
68408 duk_replace(ctx, (duk_idx_t) a);
68409
68410 break;
68411 }
68412
68413 case DUK_OP_GETPROP: {
68414 duk_context *ctx = (duk_context *) thr;
68415 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68416 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68417 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68418 duk_tval *tv_obj;
68419 duk_tval *tv_key;
68420 duk_bool_t rc;
68421
68422 /* A -> target reg
68423 * B -> object reg/const (may be const e.g. in "'foo'[1]")
68424 * C -> key reg/const
68425 */
68426
68427 tv_obj = DUK__REGCONSTP(b);
68428 tv_key = DUK__REGCONSTP(c);
68429 DUK_DDD(DUK_DDDPRINT("GETPROP: a=%ld obj=%!T, key=%!T",
68430 (long) a,
68431 (duk_tval *) DUK__REGCONSTP(b),
68432 (duk_tval *) DUK__REGCONSTP(c)));
68433 rc = duk_hobject_getprop(thr, tv_obj, tv_key); /* -> [val] */
68434 DUK_UNREF(rc); /* ignore */
68435 DUK_DDD(DUK_DDDPRINT("GETPROP --> %!T",
68436 (duk_tval *) duk_get_tval(ctx, -1)));
68437 tv_obj = NULL; /* invalidated */
68438 tv_key = NULL; /* invalidated */
68439
68440 duk_replace(ctx, (duk_idx_t) a); /* val */
68441 break;
68442 }
68443
68444 case DUK_OP_PUTPROP: {
68445 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68446 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68447 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68448 duk_tval *tv_obj;
68449 duk_tval *tv_key;
68450 duk_tval *tv_val;
68451 duk_bool_t rc;
68452
68453 /* A -> object reg
68454 * B -> key reg/const
68455 * C -> value reg/const
68456 *
68457 * Note: intentional difference to register arrangement
68458 * of e.g. GETPROP; 'A' must contain a register-only value.
68459 */
68460
68461 tv_obj = DUK__REGP(a);
68462 tv_key = DUK__REGCONSTP(b);
68463 tv_val = DUK__REGCONSTP(c);
68464 DUK_DDD(DUK_DDDPRINT("PUTPROP: obj=%!T, key=%!T, val=%!T",
68465 (duk_tval *) DUK__REGP(a),
68466 (duk_tval *) DUK__REGCONSTP(b),
68467 (duk_tval *) DUK__REGCONSTP(c)));
68468 rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, DUK__STRICT());
68469 DUK_UNREF(rc); /* ignore */
68470 DUK_DDD(DUK_DDDPRINT("PUTPROP --> obj=%!T, key=%!T, val=%!T",
68471 (duk_tval *) DUK__REGP(a),
68472 (duk_tval *) DUK__REGCONSTP(b),
68473 (duk_tval *) DUK__REGCONSTP(c)));
68474 tv_obj = NULL; /* invalidated */
68475 tv_key = NULL; /* invalidated */
68476 tv_val = NULL; /* invalidated */
68477
68478 break;
68479 }
68480
68481 case DUK_OP_DELPROP: {
68482 duk_context *ctx = (duk_context *) thr;
68483 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68484 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68485 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68486 duk_tval *tv_obj;
68487 duk_tval *tv_key;
68488 duk_bool_t rc;
68489
68490 /* A -> result reg
68491 * B -> object reg
68492 * C -> key reg/const
68493 */
68494
68495 tv_obj = DUK__REGP(b);
68496 tv_key = DUK__REGCONSTP(c);
68497 rc = duk_hobject_delprop(thr, tv_obj, tv_key, DUK__STRICT());
68498 tv_obj = NULL; /* invalidated */
68499 tv_key = NULL; /* invalidated */
68500
68501 duk_push_boolean(ctx, rc);
68502 duk_replace(ctx, (duk_idx_t) a); /* result */
68503 break;
68504 }
68505
68506 case DUK_OP_CSPROP:
68507 case DUK_OP_CSPROPI: {
68508 duk_context *ctx = (duk_context *) thr;
68509 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68510 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68511 duk_uint_fast_t idx;
68512 duk_tval *tv_obj;
68513 duk_tval *tv_key;
68514 duk_bool_t rc;
68515
68516 /* E5 Section 11.2.3, step 6.a.i */
68517 /* E5 Section 10.4.3 */
68518
68519 /* XXX: allow object to be a const, e.g. in 'foo'.toString()?
68520 * On the other hand, DUK_REGCONSTP() is slower and generates
68521 * more code.
68522 */
68523
68524 tv_obj = DUK__REGP(b);
68525 tv_key = DUK__REGCONSTP(c);
68526 rc = duk_hobject_getprop(thr, tv_obj, tv_key); /* -> [val] */
68527 DUK_UNREF(rc); /* unused */
68528 tv_obj = NULL; /* invalidated */
68529 tv_key = NULL; /* invalidated */
68530
68531 /* Note: target registers a and a+1 may overlap with DUK__REGP(b)
68532 * and DUK__REGCONSTP(c). Careful here.
68533 */
68534
68535 idx = (duk_uint_fast_t) DUK_DEC_A(ins);
68536 if (DUK_DEC_OP(ins) == DUK_OP_CSPROPI) {
68537 duk_tval *tv_ind = DUK__REGP(idx);
68538 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
68539 idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
68540 }
68541
68542#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
68543 if (idx + 2 > (duk_uint_fast_t) duk_get_top(ctx)) {
68544 /* XXX: use duk_is_valid_index() instead? */
68545 /* XXX: improve check; check against nregs, not against top */
68546 DUK__INTERNAL_ERROR("CSPROP out of bounds");
68547 }
68548#endif
68549
68550 duk_push_tval(ctx, DUK__REGP(b)); /* [ ... val obj ] */
68551 duk_replace(ctx, (duk_idx_t) (idx + 1)); /* 'this' binding */
68552 duk_replace(ctx, (duk_idx_t) idx); /* val */
68553 break;
68554 }
68555
68556 case DUK_OP_ADD:
68557 case DUK_OP_SUB:
68558 case DUK_OP_MUL:
68559 case DUK_OP_DIV:
68560 case DUK_OP_MOD: {
68561 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68562 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68563 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68564 duk_small_uint_fast_t op = DUK_DEC_OP(ins);
68565
68566 if (op == DUK_OP_ADD) {
68567 /*
68568 * Handling DUK_OP_ADD this way is more compact (experimentally)
68569 * than a separate case with separate argument decoding.
68570 */
68571 duk__vm_arith_add(thr, DUK__REGCONSTP(b), DUK__REGCONSTP(c), a);
68572 } else {
68573 duk__vm_arith_binary_op(thr, DUK__REGCONSTP(b), DUK__REGCONSTP(c), a, op);
68574 }
68575 break;
68576 }
68577
68578 case DUK_OP_BAND:
68579 case DUK_OP_BOR:
68580 case DUK_OP_BXOR:
68581 case DUK_OP_BASL:
68582 case DUK_OP_BLSR:
68583 case DUK_OP_BASR: {
68584 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68585 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68586 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68587 duk_small_uint_fast_t op = DUK_DEC_OP(ins);
68588
68589 duk__vm_bitwise_binary_op(thr, DUK__REGCONSTP(b), DUK__REGCONSTP(c), a, op);
68590 break;
68591 }
68592
68593 case DUK_OP_EQ:
68594 case DUK_OP_NEQ: {
68595 duk_context *ctx = (duk_context *) thr;
68596 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68597 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68598 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68599 duk_bool_t tmp;
68600
68601 /* E5 Sections 11.9.1, 11.9.3 */
68602 tmp = duk_js_equals(thr, DUK__REGCONSTP(b), DUK__REGCONSTP(c));
68603 if (DUK_DEC_OP(ins) == DUK_OP_NEQ) {
68604 tmp = !tmp;
68605 }
68606 duk_push_boolean(ctx, tmp);
68607 duk_replace(ctx, (duk_idx_t) a);
68608 break;
68609 }
68610
68611 case DUK_OP_SEQ:
68612 case DUK_OP_SNEQ: {
68613 duk_context *ctx = (duk_context *) thr;
68614 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68615 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68616 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68617 duk_bool_t tmp;
68618
68619 /* E5 Sections 11.9.1, 11.9.3 */
68620 tmp = duk_js_strict_equals(DUK__REGCONSTP(b), DUK__REGCONSTP(c));
68621 if (DUK_DEC_OP(ins) == DUK_OP_SNEQ) {
68622 tmp = !tmp;
68623 }
68624 duk_push_boolean(ctx, tmp);
68625 duk_replace(ctx, (duk_idx_t) a);
68626 break;
68627 }
68628
68629 /* Note: combining comparison ops must be done carefully because
68630 * of uncomparable values (NaN): it's not necessarily true that
68631 * (x >= y) === !(x < y). Also, evaluation order matters, and
68632 * although it would only seem to affect the compiler this is
68633 * actually not the case, because there are also run-time coercions
68634 * of the arguments (with potential side effects).
68635 *
68636 * XXX: can be combined; check code size.
68637 */
68638
68639 case DUK_OP_GT: {
68640 duk_context *ctx = (duk_context *) thr;
68641 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68642 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68643 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68644 duk_bool_t tmp;
68645
68646 /* x > y --> y < x */
68647 tmp = duk_js_compare_helper(thr,
68648 DUK__REGCONSTP(c), /* y */
68649 DUK__REGCONSTP(b), /* x */
68650 0); /* flags */
68651
68652 duk_push_boolean(ctx, tmp);
68653 duk_replace(ctx, (duk_idx_t) a);
68654 break;
68655 }
68656
68657 case DUK_OP_GE: {
68658 duk_context *ctx = (duk_context *) thr;
68659 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68660 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68661 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68662 duk_bool_t tmp;
68663
68664 /* x >= y --> not (x < y) */
68665 tmp = duk_js_compare_helper(thr,
68666 DUK__REGCONSTP(b), /* x */
68667 DUK__REGCONSTP(c), /* y */
68668 DUK_COMPARE_FLAG_EVAL_LEFT_FIRST |
68669 DUK_COMPARE_FLAG_NEGATE); /* flags */
68670
68671 duk_push_boolean(ctx, tmp);
68672 duk_replace(ctx, (duk_idx_t) a);
68673 break;
68674 }
68675
68676 case DUK_OP_LT: {
68677 duk_context *ctx = (duk_context *) thr;
68678 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68679 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68680 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68681 duk_bool_t tmp;
68682
68683 /* x < y */
68684 tmp = duk_js_compare_helper(thr,
68685 DUK__REGCONSTP(b), /* x */
68686 DUK__REGCONSTP(c), /* y */
68687 DUK_COMPARE_FLAG_EVAL_LEFT_FIRST); /* flags */
68688
68689 duk_push_boolean(ctx, tmp);
68690 duk_replace(ctx, (duk_idx_t) a);
68691 break;
68692 }
68693
68694 case DUK_OP_LE: {
68695 duk_context *ctx = (duk_context *) thr;
68696 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68697 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68698 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68699 duk_bool_t tmp;
68700
68701 /* x <= y --> not (x > y) --> not (y < x) */
68702 tmp = duk_js_compare_helper(thr,
68703 DUK__REGCONSTP(c), /* y */
68704 DUK__REGCONSTP(b), /* x */
68705 DUK_COMPARE_FLAG_NEGATE); /* flags */
68706
68707 duk_push_boolean(ctx, tmp);
68708 duk_replace(ctx, (duk_idx_t) a);
68709 break;
68710 }
68711
68712 case DUK_OP_IF: {
68713 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68714 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68715 duk_bool_t tmp;
68716
68717 tmp = duk_js_toboolean(DUK__REGCONSTP(b));
68718 if (tmp == (duk_bool_t) a) {
68719 /* if boolean matches A, skip next inst */
68720 curr_pc++;
68721 } else {
68722 ;
68723 }
68724 break;
68725 }
68726
68727 case DUK_OP_JUMP: {
68728 duk_int_fast_t abc = DUK_DEC_ABC(ins);
68729
68730 curr_pc += abc - DUK_BC_JUMP_BIAS;
68731 break;
68732 }
68733
68734 case DUK_OP_RETURN: {
68735 duk_context *ctx = (duk_context *) thr;
68736 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68737 duk_small_uint_fast_t b = DUK_DEC_B(ins);
68738 /* duk_small_uint_fast_t c = DUK_DEC_C(ins); */
11fdf7f2 68739 duk_small_uint_t ret_result;
7c673cae
FG
68740
68741 /* A -> flags
68742 * B -> return value reg/const
68743 * C -> currently unused
68744 */
68745
11fdf7f2 68746 DUK__SYNC_AND_NULL_CURR_PC();
7c673cae 68747
11fdf7f2
TL
68748 /* duk__handle_return() is guaranteed never to throw, except
68749 * for potential out-of-memory situations which will then
68750 * propagate out of the executor longjmp handler.
68751 */
7c673cae
FG
68752
68753 if (a & DUK_BC_RETURN_FLAG_HAVE_RETVAL) {
11fdf7f2 68754 duk_push_tval(ctx, DUK__REGCONSTP(b));
7c673cae
FG
68755 } else {
68756 duk_push_undefined(ctx);
68757 }
11fdf7f2
TL
68758 ret_result = duk__handle_return(thr,
68759 entry_thread,
68760 entry_callstack_top);
68761 if (ret_result == DUK__RETHAND_RESTART) {
68762 goto restart_execution;
68763 }
68764 DUK_ASSERT(ret_result == DUK__RETHAND_FINISHED);
7c673cae 68765
11fdf7f2
TL
68766 DUK_DDD(DUK_DDDPRINT("exiting executor after RETURN handling"));
68767 return;
7c673cae
FG
68768 }
68769
68770 case DUK_OP_CALL:
68771 case DUK_OP_CALLI: {
68772 duk_context *ctx = (duk_context *) thr;
68773 duk_small_uint_fast_t a = DUK_DEC_A(ins);
68774 duk_small_uint_fast_t c = DUK_DEC_C(ins);
68775 duk_uint_fast_t idx;
68776 duk_small_uint_t call_flags;
68777 duk_small_uint_t flag_tailcall;
68778 duk_small_uint_t flag_evalcall;
68779 duk_tval *tv_func;
68780 duk_hobject *obj_func;
68781 duk_bool_t setup_rc;
68782 duk_idx_t num_stack_args;
11fdf7f2
TL
68783#if !defined(DUK_USE_EXEC_FUN_LOCAL)
68784 duk_hcompiledfunction *fun;
68785#endif
7c673cae
FG
68786
68787 /* A -> flags
68788 * B -> base register for call (base -> func, base+1 -> this, base+2 -> arg1 ... base+2+N-1 -> argN)
68789 * (for DUK_OP_CALLI, 'b' is indirect)
68790 * C -> nargs
68791 */
68792
68793 /* these are not necessarily 0 or 1 (may be other non-zero), that's ok */
68794 flag_tailcall = (a & DUK_BC_CALL_FLAG_TAILCALL);
68795 flag_evalcall = (a & DUK_BC_CALL_FLAG_EVALCALL);
68796
68797 idx = (duk_uint_fast_t) DUK_DEC_B(ins);
68798 if (DUK_DEC_OP(ins) == DUK_OP_CALLI) {
68799 duk_tval *tv_ind = DUK__REGP(idx);
68800 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
68801 idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
68802 }
68803
68804#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
68805 if (!duk_is_valid_index(ctx, (duk_idx_t) idx)) {
68806 /* XXX: improve check; check against nregs, not against top */
68807 DUK__INTERNAL_ERROR("CALL out of bounds");
68808 }
68809#endif
68810
68811 /*
68812 * To determine whether to use an optimized Ecmascript-to-Ecmascript
68813 * call, we need to know whether the final, non-bound function is an
68814 * Ecmascript function.
68815 *
68816 * This is now implemented so that we start to do an ecma-to-ecma call
68817 * setup which will resolve the bound chain as the first thing. If the
68818 * final function is not eligible, the return value indicates that the
68819 * ecma-to-ecma call is not possible. The setup will overwrite the call
68820 * target at DUK__REGP(idx) with the final, non-bound function (which
68821 * may be a lightfunc), and fudge arguments if necessary.
68822 *
68823 * XXX: If an ecma-to-ecma call is not possible, this initial call
68824 * setup will do bound function chain resolution but won't do the
68825 * "effective this binding" resolution which is quite confusing.
68826 * Perhaps add a helper for doing bound function and effective this
68827 * binding resolution - and call that explicitly? Ecma-to-ecma call
68828 * setup and normal function handling can then assume this prestep has
68829 * been done by the caller.
68830 */
68831
68832 duk_set_top(ctx, (duk_idx_t) (idx + c + 2)); /* [ ... func this arg1 ... argN ] */
68833
68834 call_flags = 0;
68835 if (flag_tailcall) {
68836 /* We request a tail call, but in some corner cases
68837 * call handling can decide that a tail call is
68838 * actually not possible.
68839 * See: test-bug-tailcall-preventyield-assert.c.
68840 */
68841 call_flags |= DUK_CALL_FLAG_IS_TAILCALL;
68842 }
68843
68844 /* Compared to duk_handle_call():
68845 * - protected call: never
68846 * - ignore recursion limit: never
68847 */
68848 num_stack_args = c;
68849 setup_rc = duk_handle_ecma_call_setup(thr,
68850 num_stack_args,
68851 call_flags);
68852
68853 if (setup_rc) {
68854 /* Ecma-to-ecma call possible, may or may not be a tail call.
68855 * Avoid C recursion by being clever.
68856 */
68857 DUK_DDD(DUK_DDDPRINT("ecma-to-ecma call setup possible, restart execution"));
68858 /* curr_pc synced by duk_handle_ecma_call_setup() */
68859 goto restart_execution;
68860 }
68861 DUK_ASSERT(thr->ptr_curr_pc != NULL); /* restored if ecma-to-ecma setup fails */
68862
68863 DUK_DDD(DUK_DDDPRINT("ecma-to-ecma call not possible, target is native (may be lightfunc)"));
68864
68865 /* Recompute argument count: bound function handling may have shifted. */
68866 num_stack_args = duk_get_top(ctx) - (idx + 2);
68867 DUK_DDD(DUK_DDDPRINT("recomputed arg count: %ld\n", (long) num_stack_args));
68868
68869 tv_func = DUK__REGP(idx); /* Relookup if relocated */
68870 if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) {
11fdf7f2 68871
7c673cae
FG
68872 call_flags = 0; /* not protected, respect reclimit, not constructor */
68873
68874 /* There is no eval() special handling here: eval() is never
68875 * automatically converted to a lightfunc.
68876 */
68877 DUK_ASSERT(DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv_func) != duk_bi_global_object_eval);
68878
11fdf7f2
TL
68879 duk_handle_call_unprotected(thr,
68880 num_stack_args,
68881 call_flags);
7c673cae
FG
68882
68883 /* duk_js_call.c is required to restore the stack reserve
68884 * so we only need to reset the top.
68885 */
11fdf7f2
TL
68886#if !defined(DUK_USE_EXEC_FUN_LOCAL)
68887 fun = DUK__FUN();
68888#endif
7c673cae
FG
68889 duk_set_top(ctx, (duk_idx_t) fun->nregs);
68890
68891 /* No need to reinit setjmp() catchpoint, as call handling
68892 * will store and restore our state.
68893 */
68894 } else {
68895 /* Call setup checks callability. */
68896 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_func));
68897 obj_func = DUK_TVAL_GET_OBJECT(tv_func);
68898 DUK_ASSERT(obj_func != NULL);
68899 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(obj_func));
68900
68901 /*
68902 * Other cases, use C recursion.
68903 *
68904 * If a tail call was requested we ignore it and execute a normal call.
68905 * Since Duktape 0.11.0 the compiler emits a RETURN opcode even after
68906 * a tail call to avoid test-bug-tailcall-thread-yield-resume.js.
68907 *
68908 * Direct eval call: (1) call target (before following bound function
68909 * chain) is the built-in eval() function, and (2) call was made with
68910 * the identifier 'eval'.
68911 */
68912
68913 call_flags = 0; /* not protected, respect reclimit, not constructor */
68914
68915 if (DUK_HOBJECT_IS_NATIVEFUNCTION(obj_func) &&
68916 ((duk_hnativefunction *) obj_func)->func == duk_bi_global_object_eval) {
68917 if (flag_evalcall) {
68918 DUK_DDD(DUK_DDDPRINT("call target is eval, call identifier was 'eval' -> direct eval"));
68919 call_flags |= DUK_CALL_FLAG_DIRECT_EVAL;
68920 } else {
68921 DUK_DDD(DUK_DDDPRINT("call target is eval, call identifier was not 'eval' -> indirect eval"));
68922 }
68923 }
68924
11fdf7f2
TL
68925 duk_handle_call_unprotected(thr,
68926 num_stack_args,
68927 call_flags);
7c673cae
FG
68928
68929 /* duk_js_call.c is required to restore the stack reserve
68930 * so we only need to reset the top.
68931 */
11fdf7f2
TL
68932#if !defined(DUK_USE_EXEC_FUN_LOCAL)
68933 fun = DUK__FUN();
68934#endif
7c673cae
FG
68935 duk_set_top(ctx, (duk_idx_t) fun->nregs);
68936
68937 /* No need to reinit setjmp() catchpoint, as call handling
68938 * will store and restore our state.
68939 */
68940 }
68941
68942 /* When debugger is enabled, we need to recheck the activation
68943 * status after returning. This is now handled by call handling
68944 * and heap->dbg_force_restart.
68945 */
68946 break;
68947 }
68948
68949 case DUK_OP_TRYCATCH: {
68950 duk_context *ctx = (duk_context *) thr;
68951 duk_activation *act;
68952 duk_catcher *cat;
68953 duk_tval *tv1;
68954 duk_small_uint_fast_t a;
68955 duk_uint_fast_t bc;
68956
68957 /* A -> flags
68958 * BC -> reg_catch; base register for two registers used both during
68959 * trycatch setup and when catch is triggered
68960 *
68961 * If DUK_BC_TRYCATCH_FLAG_CATCH_BINDING set:
68962 * reg_catch + 0: catch binding variable name (string).
68963 * Automatic declarative environment is established for
68964 * the duration of the 'catch' clause.
68965 *
68966 * If DUK_BC_TRYCATCH_FLAG_WITH_BINDING set:
68967 * reg_catch + 0: with 'target value', which is coerced to
68968 * an object and then used as a bindind object for an
68969 * environment record. The binding is initialized here, for
68970 * the 'try' clause.
68971 *
68972 * Note that a TRYCATCH generated for a 'with' statement has no
68973 * catch or finally parts.
68974 */
68975
68976 /* XXX: TRYCATCH handling should be reworked to avoid creating
68977 * an explicit scope unless it is actually needed (e.g. function
68978 * instances or eval is executed inside the catch block). This
68979 * rework is not trivial because the compiler doesn't have an
68980 * intermediate representation. When the rework is done, the
68981 * opcode format can also be made more straightforward.
68982 */
68983
68984 /* XXX: side effect handling is quite awkward here */
68985
68986 DUK_DDD(DUK_DDDPRINT("TRYCATCH: reg_catch=%ld, have_catch=%ld, "
68987 "have_finally=%ld, catch_binding=%ld, with_binding=%ld (flags=0x%02lx)",
68988 (long) DUK_DEC_BC(ins),
68989 (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH ? 1 : 0),
68990 (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY ? 1 : 0),
68991 (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING ? 1 : 0),
68992 (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_WITH_BINDING ? 1 : 0),
68993 (unsigned long) DUK_DEC_A(ins)));
68994
68995 a = DUK_DEC_A(ins);
68996 bc = DUK_DEC_BC(ins);
68997
68998 act = thr->callstack + thr->callstack_top - 1;
68999 DUK_ASSERT(thr->callstack_top >= 1);
69000
69001 /* 'with' target must be created first, in case we run out of memory */
69002 /* XXX: refactor out? */
69003
69004 if (a & DUK_BC_TRYCATCH_FLAG_WITH_BINDING) {
69005 DUK_DDD(DUK_DDDPRINT("need to initialize a with binding object"));
69006
69007 if (act->lex_env == NULL) {
69008 DUK_ASSERT(act->var_env == NULL);
69009 DUK_DDD(DUK_DDDPRINT("delayed environment initialization"));
69010
69011 /* must relookup act in case of side effects */
69012 duk_js_init_activation_environment_records_delayed(thr, act);
69013 act = thr->callstack + thr->callstack_top - 1;
11fdf7f2 69014 DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */
7c673cae
FG
69015 }
69016 DUK_ASSERT(act->lex_env != NULL);
69017 DUK_ASSERT(act->var_env != NULL);
69018
69019 (void) duk_push_object_helper(ctx,
69020 DUK_HOBJECT_FLAG_EXTENSIBLE |
69021 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV),
69022 -1); /* no prototype, updated below */
69023
69024 duk_push_tval(ctx, DUK__REGP(bc));
69025 duk_to_object(ctx, -1);
69026 duk_dup(ctx, -1);
69027
69028 /* [ ... env target ] */
69029 /* [ ... env target target ] */
69030
69031 duk_xdef_prop_stridx(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
69032 duk_xdef_prop_stridx(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); /* always provideThis=true */
69033
69034 /* [ ... env ] */
69035
69036 DUK_DDD(DUK_DDDPRINT("environment for with binding: %!iT",
69037 (duk_tval *) duk_get_tval(ctx, -1)));
69038 }
69039
69040 /* allocate catcher and populate it (should be atomic) */
69041
69042 duk_hthread_catchstack_grow(thr);
69043 cat = thr->catchstack + thr->catchstack_top;
69044 DUK_ASSERT(thr->catchstack_top + 1 <= thr->catchstack_size);
69045 thr->catchstack_top++;
69046
69047 cat->flags = DUK_CAT_TYPE_TCF;
69048 cat->h_varname = NULL;
69049
69050 if (a & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) {
69051 cat->flags |= DUK_CAT_FLAG_CATCH_ENABLED;
69052 }
69053 if (a & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY) {
69054 cat->flags |= DUK_CAT_FLAG_FINALLY_ENABLED;
69055 }
69056 if (a & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING) {
69057 DUK_DDD(DUK_DDDPRINT("catch binding flag set to catcher"));
69058 cat->flags |= DUK_CAT_FLAG_CATCH_BINDING_ENABLED;
69059 tv1 = DUK__REGP(bc);
69060 DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
69061
69062 /* borrowed reference; although 'tv1' comes from a register,
69063 * its value was loaded using LDCONST so the constant will
69064 * also exist and be reachable.
69065 */
69066 cat->h_varname = DUK_TVAL_GET_STRING(tv1);
69067 } else if (a & DUK_BC_TRYCATCH_FLAG_WITH_BINDING) {
69068 /* env created above to stack top */
69069 duk_hobject *new_env;
69070
69071 DUK_DDD(DUK_DDDPRINT("lexenv active flag set to catcher"));
69072 cat->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE;
69073
69074 DUK_DDD(DUK_DDDPRINT("activating object env: %!iT",
69075 (duk_tval *) duk_get_tval(ctx, -1)));
11fdf7f2 69076 new_env = DUK_GET_HOBJECT_NEGIDX(ctx, -1);
7c673cae
FG
69077 DUK_ASSERT(new_env != NULL);
69078
69079 act = thr->callstack + thr->callstack_top - 1; /* relookup (side effects) */
11fdf7f2
TL
69080 DUK_ASSERT(act->lex_env != NULL);
69081 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, new_env, act->lex_env); /* side effects */
7c673cae
FG
69082
69083 act = thr->callstack + thr->callstack_top - 1; /* relookup (side effects) */
69084 act->lex_env = new_env;
69085 DUK_HOBJECT_INCREF(thr, new_env);
69086 duk_pop(ctx);
69087 } else {
69088 ;
69089 }
69090
69091 /* Registers 'bc' and 'bc + 1' are written in longjmp handling
69092 * and if their previous values (which are temporaries) become
69093 * unreachable -and- have a finalizer, there'll be a function
69094 * call during error handling which is not supported now (GH-287).
69095 * Ensure that both 'bc' and 'bc + 1' have primitive values to
69096 * guarantee no finalizer calls in error handling. Scrubbing also
69097 * ensures finalizers for the previous values run here rather than
69098 * later. Error handling related values are also written to 'bc'
69099 * and 'bc + 1' but those values never become unreachable during
69100 * error handling, so there's no side effect problem even if the
69101 * error value has a finalizer.
69102 */
69103 duk_to_undefined(ctx, bc);
69104 duk_to_undefined(ctx, bc + 1);
69105
69106 cat = thr->catchstack + thr->catchstack_top - 1; /* relookup (side effects) */
69107 cat->callstack_index = thr->callstack_top - 1;
69108 cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */
69109 cat->idx_base = (duk_size_t) (thr->valstack_bottom - thr->valstack) + bc;
69110
69111 DUK_DDD(DUK_DDDPRINT("TRYCATCH catcher: flags=0x%08lx, callstack_index=%ld, pc_base=%ld, "
69112 "idx_base=%ld, h_varname=%!O",
69113 (unsigned long) cat->flags, (long) cat->callstack_index,
69114 (long) cat->pc_base, (long) cat->idx_base, (duk_heaphdr *) cat->h_varname));
69115
69116 curr_pc += 2; /* skip jump slots */
69117 break;
69118 }
69119
69120 /* Pre/post inc/dec for register variables, important for loops. */
69121 case DUK_OP_PREINCR:
69122 case DUK_OP_PREDECR:
69123 case DUK_OP_POSTINCR:
69124 case DUK_OP_POSTDECR: {
69125 duk_context *ctx = (duk_context *) thr;
69126 duk_small_uint_fast_t a = DUK_DEC_A(ins);
69127 duk_uint_fast_t bc = DUK_DEC_BC(ins);
69128 duk_tval *tv1, *tv2;
7c673cae
FG
69129 duk_double_t x, y, z;
69130
69131 /* Two lowest bits of opcode are used to distinguish
69132 * variants. Bit 0 = inc(0)/dec(1), bit 1 = pre(0)/post(1).
69133 */
69134 DUK_ASSERT((DUK_OP_PREINCR & 0x03) == 0x00);
69135 DUK_ASSERT((DUK_OP_PREDECR & 0x03) == 0x01);
69136 DUK_ASSERT((DUK_OP_POSTINCR & 0x03) == 0x02);
69137 DUK_ASSERT((DUK_OP_POSTDECR & 0x03) == 0x03);
69138
69139 tv1 = DUK__REGP(bc);
69140#if defined(DUK_USE_FASTINT)
69141 if (DUK_TVAL_IS_FASTINT(tv1)) {
69142 duk_int64_t x_fi, y_fi, z_fi;
69143 x_fi = DUK_TVAL_GET_FASTINT(tv1);
69144 if (ins & DUK_ENC_OP(0x01)) {
69145 if (x_fi == DUK_FASTINT_MIN) {
69146 goto skip_fastint;
69147 }
69148 y_fi = x_fi - 1;
69149 } else {
69150 if (x_fi == DUK_FASTINT_MAX) {
69151 goto skip_fastint;
69152 }
69153 y_fi = x_fi + 1;
69154 }
69155
69156 DUK_TVAL_SET_FASTINT(tv1, y_fi); /* no need for refcount update */
69157
69158 tv2 = DUK__REGP(a);
7c673cae 69159 z_fi = (ins & DUK_ENC_OP(0x02)) ? x_fi : y_fi;
11fdf7f2 69160 DUK_TVAL_SET_FASTINT_UPDREF(thr, tv2, z_fi); /* side effects */
7c673cae
FG
69161 break;
69162 }
69163 skip_fastint:
69164#endif
69165 if (DUK_TVAL_IS_NUMBER(tv1)) {
69166 /* Fast path for the case where the register
69167 * is a number (e.g. loop counter).
69168 */
69169
69170 x = DUK_TVAL_GET_NUMBER(tv1);
69171 if (ins & DUK_ENC_OP(0x01)) {
69172 y = x - 1.0;
69173 } else {
69174 y = x + 1.0;
69175 }
69176
69177 DUK_TVAL_SET_NUMBER(tv1, y); /* no need for refcount update */
69178 } else {
69179 x = duk_to_number(ctx, bc);
69180
69181 if (ins & DUK_ENC_OP(0x01)) {
69182 y = x - 1.0;
69183 } else {
69184 y = x + 1.0;
69185 }
69186
69187 duk_push_number(ctx, y);
69188 duk_replace(ctx, bc);
69189 }
69190
69191 tv2 = DUK__REGP(a);
7c673cae 69192 z = (ins & DUK_ENC_OP(0x02)) ? x : y;
11fdf7f2 69193 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv2, z); /* side effects */
7c673cae
FG
69194 break;
69195 }
69196
69197 /* Preinc/predec for var-by-name, slow path. */
69198 case DUK_OP_PREINCV:
69199 case DUK_OP_PREDECV:
69200 case DUK_OP_POSTINCV:
69201 case DUK_OP_POSTDECV: {
69202 duk_context *ctx = (duk_context *) thr;
69203 duk_activation *act;
69204 duk_small_uint_fast_t a = DUK_DEC_A(ins);
69205 duk_uint_fast_t bc = DUK_DEC_BC(ins);
69206 duk_double_t x, y;
69207 duk_tval *tv1;
69208 duk_hstring *name;
69209
69210 /* Two lowest bits of opcode are used to distinguish
69211 * variants. Bit 0 = inc(0)/dec(1), bit 1 = pre(0)/post(1).
69212 */
69213 DUK_ASSERT((DUK_OP_PREINCV & 0x03) == 0x00);
69214 DUK_ASSERT((DUK_OP_PREDECV & 0x03) == 0x01);
69215 DUK_ASSERT((DUK_OP_POSTINCV & 0x03) == 0x02);
69216 DUK_ASSERT((DUK_OP_POSTDECV & 0x03) == 0x03);
69217
69218 tv1 = DUK__CONSTP(bc);
69219 DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
69220 name = DUK_TVAL_GET_STRING(tv1);
69221 DUK_ASSERT(name != NULL);
69222 act = thr->callstack + thr->callstack_top - 1;
69223 (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */
69224
69225 /* XXX: fastint fast path would be very useful here */
69226
69227 x = duk_to_number(ctx, -2);
69228 duk_pop_2(ctx);
69229 if (ins & DUK_ENC_OP(0x01)) {
69230 y = x - 1.0;
69231 } else {
69232 y = x + 1.0;
69233 }
69234
69235 duk_push_number(ctx, y);
11fdf7f2 69236 tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1);
7c673cae 69237 DUK_ASSERT(tv1 != NULL);
11fdf7f2 69238 act = thr->callstack + thr->callstack_top - 1;
7c673cae
FG
69239 duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT());
69240 duk_pop(ctx);
69241
69242 duk_push_number(ctx, (ins & DUK_ENC_OP(0x02)) ? x : y);
69243 duk_replace(ctx, (duk_idx_t) a);
69244 break;
69245 }
69246
69247 /* Preinc/predec for object properties. */
69248 case DUK_OP_PREINCP:
69249 case DUK_OP_PREDECP:
69250 case DUK_OP_POSTINCP:
69251 case DUK_OP_POSTDECP: {
69252 duk_context *ctx = (duk_context *) thr;
69253 duk_small_uint_fast_t a = DUK_DEC_A(ins);
69254 duk_small_uint_fast_t b = DUK_DEC_B(ins);
69255 duk_small_uint_fast_t c = DUK_DEC_C(ins);
69256 duk_tval *tv_obj;
69257 duk_tval *tv_key;
69258 duk_tval *tv_val;
69259 duk_bool_t rc;
69260 duk_double_t x, y;
69261
69262 /* A -> target reg
69263 * B -> object reg/const (may be const e.g. in "'foo'[1]")
69264 * C -> key reg/const
69265 */
69266
69267 /* Two lowest bits of opcode are used to distinguish
69268 * variants. Bit 0 = inc(0)/dec(1), bit 1 = pre(0)/post(1).
69269 */
69270 DUK_ASSERT((DUK_OP_PREINCP & 0x03) == 0x00);
69271 DUK_ASSERT((DUK_OP_PREDECP & 0x03) == 0x01);
69272 DUK_ASSERT((DUK_OP_POSTINCP & 0x03) == 0x02);
69273 DUK_ASSERT((DUK_OP_POSTDECP & 0x03) == 0x03);
69274
69275 tv_obj = DUK__REGCONSTP(b);
69276 tv_key = DUK__REGCONSTP(c);
69277 rc = duk_hobject_getprop(thr, tv_obj, tv_key); /* -> [val] */
69278 DUK_UNREF(rc); /* ignore */
69279 tv_obj = NULL; /* invalidated */
69280 tv_key = NULL; /* invalidated */
69281
69282 x = duk_to_number(ctx, -1);
69283 duk_pop(ctx);
69284 if (ins & DUK_ENC_OP(0x01)) {
69285 y = x - 1.0;
69286 } else {
69287 y = x + 1.0;
69288 }
69289
69290 duk_push_number(ctx, y);
11fdf7f2 69291 tv_val = DUK_GET_TVAL_NEGIDX(ctx, -1);
7c673cae
FG
69292 DUK_ASSERT(tv_val != NULL);
69293 tv_obj = DUK__REGCONSTP(b);
69294 tv_key = DUK__REGCONSTP(c);
69295 rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, DUK__STRICT());
69296 DUK_UNREF(rc); /* ignore */
69297 tv_obj = NULL; /* invalidated */
69298 tv_key = NULL; /* invalidated */
69299 duk_pop(ctx);
69300
69301 duk_push_number(ctx, (ins & DUK_ENC_OP(0x02)) ? x : y);
69302 duk_replace(ctx, (duk_idx_t) a);
69303 break;
69304 }
69305
69306 case DUK_OP_EXTRA: {
69307 /* XXX: shared decoding of 'b' and 'c'? */
69308
69309 duk_small_uint_fast_t extraop = DUK_DEC_A(ins);
69310 switch ((int) extraop) {
69311 /* XXX: switch cast? */
69312
69313 case DUK_EXTRAOP_NOP: {
69314 /* nop */
69315 break;
69316 }
69317
69318 case DUK_EXTRAOP_INVALID: {
11fdf7f2 69319 DUK_ERROR_FMT1(thr, DUK_ERR_INTERNAL_ERROR, "INVALID opcode (%ld)", (long) DUK_DEC_BC(ins));
7c673cae
FG
69320 break;
69321 }
69322
69323 case DUK_EXTRAOP_LDTHIS: {
69324 /* Note: 'this' may be bound to any value, not just an object */
69325 duk_uint_fast_t bc = DUK_DEC_BC(ins);
7c673cae
FG
69326 duk_tval *tv1, *tv2;
69327
69328 tv1 = DUK__REGP(bc);
69329 tv2 = thr->valstack_bottom - 1; /* 'this binding' is just under bottom */
69330 DUK_ASSERT(tv2 >= thr->valstack);
69331
69332 DUK_DDD(DUK_DDDPRINT("LDTHIS: %!T to r%ld", (duk_tval *) tv2, (long) bc));
69333
11fdf7f2 69334 DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv1, tv2); /* side effects */
7c673cae
FG
69335 break;
69336 }
69337
69338 case DUK_EXTRAOP_LDUNDEF: {
69339 duk_uint_fast_t bc = DUK_DEC_BC(ins);
7c673cae
FG
69340 duk_tval *tv1;
69341
69342 tv1 = DUK__REGP(bc);
11fdf7f2 69343 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */
7c673cae
FG
69344 break;
69345 }
69346
69347 case DUK_EXTRAOP_LDNULL: {
69348 duk_uint_fast_t bc = DUK_DEC_BC(ins);
7c673cae
FG
69349 duk_tval *tv1;
69350
69351 tv1 = DUK__REGP(bc);
11fdf7f2 69352 DUK_TVAL_SET_NULL_UPDREF(thr, tv1); /* side effects */
7c673cae
FG
69353 break;
69354 }
69355
69356 case DUK_EXTRAOP_LDTRUE:
69357 case DUK_EXTRAOP_LDFALSE: {
69358 duk_uint_fast_t bc = DUK_DEC_BC(ins);
7c673cae
FG
69359 duk_tval *tv1;
69360 duk_small_uint_fast_t bval = (extraop == DUK_EXTRAOP_LDTRUE ? 1 : 0);
69361
69362 tv1 = DUK__REGP(bc);
11fdf7f2 69363 DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv1, bval); /* side effects */
7c673cae
FG
69364 break;
69365 }
69366
69367 case DUK_EXTRAOP_NEWOBJ: {
69368 duk_context *ctx = (duk_context *) thr;
69369 duk_small_uint_fast_t b = DUK_DEC_B(ins);
69370
69371 duk_push_object(ctx);
69372 duk_replace(ctx, (duk_idx_t) b);
69373 break;
69374 }
69375
69376 case DUK_EXTRAOP_NEWARR: {
69377 duk_context *ctx = (duk_context *) thr;
69378 duk_small_uint_fast_t b = DUK_DEC_B(ins);
69379
69380 duk_push_array(ctx);
69381 duk_replace(ctx, (duk_idx_t) b);
69382 break;
69383 }
69384
69385 case DUK_EXTRAOP_SETALEN: {
69386 duk_small_uint_fast_t b;
69387 duk_small_uint_fast_t c;
69388 duk_tval *tv1;
69389 duk_hobject *h;
69390 duk_uint32_t len;
69391
69392 b = DUK_DEC_B(ins); tv1 = DUK__REGP(b);
69393 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1));
69394 h = DUK_TVAL_GET_OBJECT(tv1);
69395
69396 c = DUK_DEC_C(ins); tv1 = DUK__REGP(c);
69397 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
69398 len = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv1);
69399
69400 duk_hobject_set_length(thr, h, len);
69401
69402 break;
69403 }
69404
69405 case DUK_EXTRAOP_TYPEOF: {
69406 duk_context *ctx = (duk_context *) thr;
69407 duk_uint_fast_t bc = DUK_DEC_BC(ins);
69408 duk_push_hstring(ctx, duk_js_typeof(thr, DUK__REGP(bc)));
69409 duk_replace(ctx, (duk_idx_t) bc);
69410 break;
69411 }
69412
69413 case DUK_EXTRAOP_TYPEOFID: {
69414 duk_context *ctx = (duk_context *) thr;
69415 duk_activation *act;
69416 duk_small_uint_fast_t b = DUK_DEC_B(ins);
69417 duk_small_uint_fast_t c = DUK_DEC_C(ins);
69418 duk_hstring *name;
69419 duk_tval *tv;
69420
69421 /* B -> target register
69422 * C -> constant index of identifier name
69423 */
69424
69425 tv = DUK__REGCONSTP(c); /* XXX: this could be a DUK__CONSTP instead */
69426 DUK_ASSERT(DUK_TVAL_IS_STRING(tv));
69427 name = DUK_TVAL_GET_STRING(tv);
69428 act = thr->callstack + thr->callstack_top - 1;
69429 if (duk_js_getvar_activation(thr, act, name, 0 /*throw*/)) {
69430 /* -> [... val this] */
11fdf7f2 69431 tv = DUK_GET_TVAL_NEGIDX(ctx, -2);
7c673cae
FG
69432 duk_push_hstring(ctx, duk_js_typeof(thr, tv));
69433 duk_replace(ctx, (duk_idx_t) b);
69434 duk_pop_2(ctx);
69435 } else {
69436 /* unresolvable, no stack changes */
69437 duk_push_hstring_stridx(ctx, DUK_STRIDX_LC_UNDEFINED);
69438 duk_replace(ctx, (duk_idx_t) b);
69439 }
69440
69441 break;
69442 }
69443
69444 case DUK_EXTRAOP_INITENUM: {
69445 duk_context *ctx = (duk_context *) thr;
69446 duk_small_uint_fast_t b = DUK_DEC_B(ins);
69447 duk_small_uint_fast_t c = DUK_DEC_C(ins);
69448
69449 /*
69450 * Enumeration semantics come from for-in statement, E5 Section 12.6.4.
69451 * If called with 'null' or 'undefined', this opcode returns 'null' as
69452 * the enumerator, which is special cased in NEXTENUM. This simplifies
69453 * the compiler part
69454 */
69455
69456 /* B -> register for writing enumerator object
69457 * C -> value to be enumerated (register)
69458 */
69459
69460 if (duk_is_null_or_undefined(ctx, (duk_idx_t) c)) {
69461 duk_push_null(ctx);
69462 duk_replace(ctx, (duk_idx_t) b);
69463 } else {
69464 duk_dup(ctx, (duk_idx_t) c);
69465 duk_to_object(ctx, -1);
69466 duk_hobject_enumerator_create(ctx, 0 /*enum_flags*/); /* [ ... val ] --> [ ... enum ] */
69467 duk_replace(ctx, (duk_idx_t) b);
69468 }
69469 break;
69470 }
69471
69472 case DUK_EXTRAOP_NEXTENUM: {
69473 duk_context *ctx = (duk_context *) thr;
69474 duk_small_uint_fast_t b = DUK_DEC_B(ins);
69475 duk_small_uint_fast_t c = DUK_DEC_C(ins);
69476
69477 /*
69478 * NEXTENUM checks whether the enumerator still has unenumerated
69479 * keys. If so, the next key is loaded to the target register
69480 * and the next instruction is skipped. Otherwise the next instruction
69481 * will be executed, jumping out of the enumeration loop.
69482 */
69483
69484 /* B -> target register for next key
69485 * C -> enum register
69486 */
69487
69488 DUK_DDD(DUK_DDDPRINT("NEXTENUM: b->%!T, c->%!T",
69489 (duk_tval *) duk_get_tval(ctx, (duk_idx_t) b),
69490 (duk_tval *) duk_get_tval(ctx, (duk_idx_t) c)));
69491
69492 if (duk_is_object(ctx, (duk_idx_t) c)) {
69493 /* XXX: assert 'c' is an enumerator */
69494 duk_dup(ctx, (duk_idx_t) c);
69495 if (duk_hobject_enumerator_next(ctx, 0 /*get_value*/)) {
69496 /* [ ... enum ] -> [ ... next_key ] */
69497 DUK_DDD(DUK_DDDPRINT("enum active, next key is %!T, skip jump slot ",
69498 (duk_tval *) duk_get_tval(ctx, -1)));
69499 curr_pc++;
69500 } else {
69501 /* [ ... enum ] -> [ ... ] */
69502 DUK_DDD(DUK_DDDPRINT("enum finished, execute jump slot"));
69503 duk_push_undefined(ctx);
69504 }
69505 duk_replace(ctx, (duk_idx_t) b);
69506 } else {
69507 /* 'null' enumerator case -> behave as with an empty enumerator */
69508 DUK_ASSERT(duk_is_null(ctx, (duk_idx_t) c));
69509 DUK_DDD(DUK_DDDPRINT("enum is null, execute jump slot"));
69510 }
69511 break;
69512 }
69513
69514 case DUK_EXTRAOP_INITSET:
69515 case DUK_EXTRAOP_INITSETI:
69516 case DUK_EXTRAOP_INITGET:
69517 case DUK_EXTRAOP_INITGETI: {
69518 duk_context *ctx = (duk_context *) thr;
69519 duk_bool_t is_set = (extraop == DUK_EXTRAOP_INITSET || extraop == DUK_EXTRAOP_INITSETI);
69520 duk_small_uint_fast_t b = DUK_DEC_B(ins);
69521 duk_uint_fast_t idx;
69522
69523 /* B -> object register
69524 * C -> C+0 contains key, C+1 closure (value)
69525 */
69526
69527 /*
69528 * INITSET/INITGET are only used to initialize object literal keys.
69529 * The compiler ensures that there cannot be a previous data property
69530 * of the same name. It also ensures that setter and getter can only
69531 * be initialized once (or not at all).
69532 */
69533
69534 idx = (duk_uint_fast_t) DUK_DEC_C(ins);
69535 if (extraop == DUK_EXTRAOP_INITSETI || extraop == DUK_EXTRAOP_INITGETI) {
69536 duk_tval *tv_ind = DUK__REGP(idx);
69537 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
69538 idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
69539 }
69540
69541#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
69542 if (idx + 2 > (duk_uint_fast_t) duk_get_top(ctx)) {
69543 /* XXX: use duk_is_valid_index() instead? */
69544 /* XXX: improve check; check against nregs, not against top */
69545 DUK__INTERNAL_ERROR("INITSET/INITGET out of bounds");
69546 }
69547#endif
69548
69549 /* XXX: this is now a very unoptimal implementation -- this can be
69550 * made very simple by direct manipulation of the object internals,
69551 * given the guarantees above.
69552 */
69553
69554 duk_push_hobject_bidx(ctx, DUK_BIDX_OBJECT_CONSTRUCTOR);
69555 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_DEFINE_PROPERTY);
69556 duk_push_undefined(ctx);
69557 duk_dup(ctx, (duk_idx_t) b);
69558 duk_dup(ctx, (duk_idx_t) (idx + 0));
69559 duk_push_object(ctx); /* -> [ Object defineProperty undefined obj key desc ] */
69560
69561 duk_push_true(ctx);
69562 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_ENUMERABLE);
69563 duk_push_true(ctx);
69564 duk_put_prop_stridx(ctx, -2, DUK_STRIDX_CONFIGURABLE);
69565 duk_dup(ctx, (duk_idx_t) (idx + 1));
69566 duk_put_prop_stridx(ctx, -2, (is_set ? DUK_STRIDX_SET : DUK_STRIDX_GET));
69567
69568 DUK_DDD(DUK_DDDPRINT("INITGET/INITSET: obj=%!T, key=%!T, desc=%!T",
69569 (duk_tval *) duk_get_tval(ctx, -3),
69570 (duk_tval *) duk_get_tval(ctx, -2),
69571 (duk_tval *) duk_get_tval(ctx, -1)));
69572
69573 duk_call_method(ctx, 3); /* -> [ Object res ] */
69574 duk_pop_2(ctx);
69575
69576 DUK_DDD(DUK_DDDPRINT("INITGET/INITSET AFTER: obj=%!T",
69577 (duk_tval *) duk_get_tval(ctx, (duk_idx_t) b)));
69578 break;
69579 }
69580
69581 case DUK_EXTRAOP_ENDTRY: {
69582 duk_catcher *cat;
7c673cae
FG
69583 duk_tval *tv1;
69584
69585 DUK_ASSERT(thr->catchstack_top >= 1);
69586 DUK_ASSERT(thr->callstack_top >= 1);
69587 DUK_ASSERT(thr->catchstack[thr->catchstack_top - 1].callstack_index == thr->callstack_top - 1);
69588
69589 cat = thr->catchstack + thr->catchstack_top - 1;
69590
69591 DUK_DDD(DUK_DDDPRINT("ENDTRY: clearing catch active flag (regardless of whether it was set or not)"));
69592 DUK_CAT_CLEAR_CATCH_ENABLED(cat);
69593
69594 if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
69595 DUK_DDD(DUK_DDDPRINT("ENDTRY: finally part is active, jump through 2nd jump slot with 'normal continuation'"));
69596
69597 tv1 = thr->valstack + cat->idx_base;
69598 DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
11fdf7f2 69599 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */
7c673cae
FG
69600 tv1 = NULL;
69601
69602 tv1 = thr->valstack + cat->idx_base + 1;
69603 DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
11fdf7f2 69604 DUK_TVAL_SET_FASTINT_U32_UPDREF(thr, tv1, (duk_uint32_t) DUK_LJ_TYPE_NORMAL); /* side effects */
7c673cae
FG
69605 tv1 = NULL;
69606
69607 DUK_CAT_CLEAR_FINALLY_ENABLED(cat);
69608 } else {
69609 DUK_DDD(DUK_DDDPRINT("ENDTRY: no finally part, dismantle catcher, jump through 2nd jump slot (to end of statement)"));
69610 duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
69611 /* no need to unwind callstack */
69612 }
69613
69614 curr_pc = cat->pc_base + 1;
69615 break;
69616 }
69617
69618 case DUK_EXTRAOP_ENDCATCH: {
69619 duk_activation *act;
69620 duk_catcher *cat;
7c673cae
FG
69621 duk_tval *tv1;
69622
69623 DUK_ASSERT(thr->catchstack_top >= 1);
69624 DUK_ASSERT(thr->callstack_top >= 1);
69625 DUK_ASSERT(thr->catchstack[thr->catchstack_top - 1].callstack_index == thr->callstack_top - 1);
69626
69627 cat = thr->catchstack + thr->catchstack_top - 1;
69628 DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat)); /* cleared before entering catch part */
69629
69630 act = thr->callstack + thr->callstack_top - 1;
69631
69632 if (DUK_CAT_HAS_LEXENV_ACTIVE(cat)) {
69633 duk_hobject *prev_env;
69634
69635 /* 'with' binding has no catch clause, so can't be here unless a normal try-catch */
69636 DUK_ASSERT(DUK_CAT_HAS_CATCH_BINDING_ENABLED(cat));
69637 DUK_ASSERT(act->lex_env != NULL);
69638
69639 DUK_DDD(DUK_DDDPRINT("ENDCATCH: popping catcher part lexical environment"));
69640
69641 prev_env = act->lex_env;
69642 DUK_ASSERT(prev_env != NULL);
69643 act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, prev_env);
69644 DUK_CAT_CLEAR_LEXENV_ACTIVE(cat);
69645 DUK_HOBJECT_DECREF(thr, prev_env); /* side effects */
69646 }
69647
69648 if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
69649 DUK_DDD(DUK_DDDPRINT("ENDCATCH: finally part is active, jump through 2nd jump slot with 'normal continuation'"));
69650
69651 tv1 = thr->valstack + cat->idx_base;
69652 DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
11fdf7f2 69653 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */
7c673cae
FG
69654 tv1 = NULL;
69655
69656 tv1 = thr->valstack + cat->idx_base + 1;
69657 DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
11fdf7f2 69658 DUK_TVAL_SET_FASTINT_U32_UPDREF(thr, tv1, (duk_uint32_t) DUK_LJ_TYPE_NORMAL); /* side effects */
7c673cae
FG
69659 tv1 = NULL;
69660
69661 DUK_CAT_CLEAR_FINALLY_ENABLED(cat);
69662 } else {
69663 DUK_DDD(DUK_DDDPRINT("ENDCATCH: no finally part, dismantle catcher, jump through 2nd jump slot (to end of statement)"));
69664 duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
69665 /* no need to unwind callstack */
69666 }
69667
69668 curr_pc = cat->pc_base + 1;
69669 break;
69670 }
69671
69672 case DUK_EXTRAOP_ENDFIN: {
69673 duk_context *ctx = (duk_context *) thr;
69674 duk_catcher *cat;
69675 duk_tval *tv1;
11fdf7f2
TL
69676 duk_small_uint_t cont_type;
69677 duk_small_uint_t ret_result;
69678
69679 /* Sync and NULL early. */
69680 DUK__SYNC_AND_NULL_CURR_PC();
7c673cae
FG
69681
69682 DUK_ASSERT(thr->catchstack_top >= 1);
69683 DUK_ASSERT(thr->callstack_top >= 1);
69684 DUK_ASSERT(thr->catchstack[thr->catchstack_top - 1].callstack_index == thr->callstack_top - 1);
69685
69686 cat = thr->catchstack + thr->catchstack_top - 1;
69687
69688 /* CATCH flag may be enabled or disabled here; it may be enabled if
69689 * the statement has a catch block but the try block does not throw
69690 * an error.
69691 */
69692 DUK_ASSERT(!DUK_CAT_HAS_FINALLY_ENABLED(cat)); /* cleared before entering finally */
69693 /* XXX: assert idx_base */
69694
69695 DUK_DDD(DUK_DDDPRINT("ENDFIN: completion value=%!T, type=%!T",
69696 (duk_tval *) (thr->valstack + cat->idx_base + 0),
69697 (duk_tval *) (thr->valstack + cat->idx_base + 1)));
69698
69699 tv1 = thr->valstack + cat->idx_base + 1; /* type */
69700 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
11fdf7f2 69701 cont_type = (duk_small_uint_t) DUK_TVAL_GET_NUMBER(tv1);
7c673cae 69702
11fdf7f2
TL
69703 switch (cont_type) {
69704 case DUK_LJ_TYPE_NORMAL: {
7c673cae
FG
69705 DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with 'normal' (non-abrupt) completion -> "
69706 "dismantle catcher, resume execution after ENDFIN"));
69707 duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
69708 /* no need to unwind callstack */
11fdf7f2
TL
69709 goto restart_execution;
69710 }
69711 case DUK_LJ_TYPE_RETURN: {
69712 DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with 'return' complation -> dismantle "
69713 "catcher, handle return, lj.value1=%!T", thr->valstack + cat->idx_base));
69714
69715 /* Not necessary to unwind catchstack: return handling will
69716 * do it. The finally flag of 'cat' is no longer set. The
69717 * catch flag may be set, but it's not checked by return handling.
69718 */
69719 DUK_ASSERT(!DUK_CAT_HAS_FINALLY_ENABLED(cat)); /* cleared before entering finally */
69720#if 0
69721 duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
69722#endif
69723
69724 duk_push_tval(ctx, thr->valstack + cat->idx_base);
69725 ret_result = duk__handle_return(thr,
69726 entry_thread,
69727 entry_callstack_top);
69728 if (ret_result == DUK__RETHAND_RESTART) {
69729 goto restart_execution;
69730 }
69731 DUK_ASSERT(ret_result == DUK__RETHAND_FINISHED);
69732
69733 DUK_DDD(DUK_DDDPRINT("exiting executor after ENDFIN and RETURN (pseudo) longjmp type"));
69734 return;
69735 }
69736 case DUK_LJ_TYPE_BREAK:
69737 case DUK_LJ_TYPE_CONTINUE: {
69738 duk_uint_t label_id;
69739 duk_small_uint_t lj_type;
69740
69741 /* Not necessary to unwind catchstack: break/continue
69742 * handling will do it. The finally flag of 'cat' is
69743 * no longer set. The catch flag may be set, but it's
69744 * not checked by break/continue handling.
69745 */
69746#if 0
69747 duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
69748#endif
69749
69750 tv1 = thr->valstack + cat->idx_base;
69751 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
69752#if defined(DUK_USE_FASTINT)
69753 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1));
69754 label_id = (duk_small_uint_t) DUK_TVAL_GET_FASTINT_U32(tv1);
69755#else
69756 label_id = (duk_small_uint_t) DUK_TVAL_GET_NUMBER(tv1);
69757#endif
69758 lj_type = cont_type;
69759 duk__handle_break_or_continue(thr, label_id, lj_type);
69760 goto restart_execution;
69761 }
69762 default: {
7c673cae
FG
69763 DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with abrupt completion, lj_type=%ld -> "
69764 "dismantle catcher, re-throw error",
69765 (long) cont_type));
69766
69767 duk_push_tval(ctx, thr->valstack + cat->idx_base);
69768
7c673cae
FG
69769 duk_err_setup_heap_ljstate(thr, (duk_small_int_t) cont_type);
69770
69771 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */
7c673cae
FG
69772 duk_err_longjmp(thr);
69773 DUK_UNREACHABLE();
69774 }
11fdf7f2 69775 }
7c673cae 69776
11fdf7f2
TL
69777 /* Must restart in all cases because we NULLed thr->ptr_curr_pc. */
69778 DUK_UNREACHABLE();
7c673cae
FG
69779 break;
69780 }
69781
69782 case DUK_EXTRAOP_THROW: {
69783 duk_context *ctx = (duk_context *) thr;
69784 duk_uint_fast_t bc = DUK_DEC_BC(ins);
69785
69786 /* Note: errors are augmented when they are created, not
69787 * when they are thrown. So, don't augment here, it would
69788 * break re-throwing for instance.
69789 */
69790
69791 /* Sync so that augmentation sees up-to-date activations, NULL
69792 * thr->ptr_curr_pc so that it's not used if side effects occur
69793 * in augmentation or longjmp handling.
69794 */
69795 DUK__SYNC_AND_NULL_CURR_PC();
69796
69797 duk_dup(ctx, (duk_idx_t) bc);
69798 DUK_DDD(DUK_DDDPRINT("THROW ERROR (BYTECODE): %!dT (before throw augment)",
69799 (duk_tval *) duk_get_tval(ctx, -1)));
69800#if defined(DUK_USE_AUGMENT_ERROR_THROW)
69801 duk_err_augment_error_throw(thr);
69802 DUK_DDD(DUK_DDDPRINT("THROW ERROR (BYTECODE): %!dT (after throw augment)",
69803 (duk_tval *) duk_get_tval(ctx, -1)));
69804#endif
69805
69806 duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW);
69807
69808 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */
69809 duk_err_longjmp(thr);
69810 DUK_UNREACHABLE();
69811 break;
69812 }
69813
69814 case DUK_EXTRAOP_INVLHS: {
69815 DUK_ERROR(thr, DUK_ERR_REFERENCE_ERROR, "invalid lvalue");
69816
69817 DUK_UNREACHABLE();
69818 break;
69819 }
69820
69821 case DUK_EXTRAOP_UNM:
69822 case DUK_EXTRAOP_UNP: {
69823 duk_uint_fast_t bc = DUK_DEC_BC(ins);
69824 duk__vm_arith_unary_op(thr, DUK__REGP(bc), bc, extraop);
69825 break;
69826 }
69827
69828 case DUK_EXTRAOP_DEBUGGER: {
69829 /* Opcode only emitted by compiler when debugger
69830 * support is enabled. Ignore it silently without
69831 * debugger support, in case it has been loaded
69832 * from precompiled bytecode.
69833 */
69834#if defined(DUK_USE_DEBUGGER_SUPPORT)
7c673cae 69835 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
11fdf7f2
TL
69836 DUK_D(DUK_DPRINT("DEBUGGER statement encountered, halt execution"));
69837 DUK__SYNC_AND_NULL_CURR_PC();
69838 duk_debug_halt_execution(thr, 1 /*use_prev_pc*/);
69839 DUK_D(DUK_DPRINT("DEBUGGER statement finished, resume execution"));
7c673cae 69840 goto restart_execution;
11fdf7f2
TL
69841 } else {
69842 DUK_D(DUK_DPRINT("DEBUGGER statement ignored, debugger not attached"));
7c673cae
FG
69843 }
69844#else
69845 DUK_D(DUK_DPRINT("DEBUGGER statement ignored, no debugger support"));
69846#endif
69847 break;
69848 }
69849
69850 case DUK_EXTRAOP_BREAK: {
7c673cae
FG
69851 duk_uint_fast_t bc = DUK_DEC_BC(ins);
69852
7c673cae
FG
69853 DUK_DDD(DUK_DDDPRINT("BREAK: %ld", (long) bc));
69854
7c673cae 69855 DUK__SYNC_AND_NULL_CURR_PC();
11fdf7f2
TL
69856 duk__handle_break_or_continue(thr, (duk_uint_t) bc, DUK_LJ_TYPE_BREAK);
69857 goto restart_execution;
7c673cae
FG
69858 }
69859
69860 case DUK_EXTRAOP_CONTINUE: {
7c673cae
FG
69861 duk_uint_fast_t bc = DUK_DEC_BC(ins);
69862
7c673cae
FG
69863 DUK_DDD(DUK_DDDPRINT("CONTINUE: %ld", (long) bc));
69864
7c673cae 69865 DUK__SYNC_AND_NULL_CURR_PC();
11fdf7f2
TL
69866 duk__handle_break_or_continue(thr, (duk_uint_t) bc, DUK_LJ_TYPE_CONTINUE);
69867 goto restart_execution;
7c673cae
FG
69868 }
69869
69870 case DUK_EXTRAOP_BNOT: {
69871 duk_uint_fast_t bc = DUK_DEC_BC(ins);
69872
69873 duk__vm_bitwise_not(thr, DUK__REGP(bc), bc);
69874 break;
69875 }
69876
69877 case DUK_EXTRAOP_LNOT: {
69878 duk_uint_fast_t bc = DUK_DEC_BC(ins);
69879 duk_tval *tv1;
69880
69881 tv1 = DUK__REGP(bc);
69882 duk__vm_logical_not(thr, tv1, tv1);
69883 break;
69884 }
69885
69886 case DUK_EXTRAOP_INSTOF: {
69887 duk_context *ctx = (duk_context *) thr;
69888 duk_small_uint_fast_t b = DUK_DEC_B(ins);
69889 duk_small_uint_fast_t c = DUK_DEC_C(ins);
69890 duk_bool_t tmp;
69891
69892 tmp = duk_js_instanceof(thr, DUK__REGP(b), DUK__REGCONSTP(c));
69893 duk_push_boolean(ctx, tmp);
69894 duk_replace(ctx, (duk_idx_t) b);
69895 break;
69896 }
69897
69898 case DUK_EXTRAOP_IN: {
69899 duk_context *ctx = (duk_context *) thr;
69900 duk_small_uint_fast_t b = DUK_DEC_B(ins);
69901 duk_small_uint_fast_t c = DUK_DEC_C(ins);
69902 duk_bool_t tmp;
69903
69904 tmp = duk_js_in(thr, DUK__REGP(b), DUK__REGCONSTP(c));
69905 duk_push_boolean(ctx, tmp);
69906 duk_replace(ctx, (duk_idx_t) b);
69907 break;
69908 }
69909
69910 case DUK_EXTRAOP_LABEL: {
69911 duk_catcher *cat;
69912 duk_uint_fast_t bc = DUK_DEC_BC(ins);
69913
69914 /* allocate catcher and populate it (should be atomic) */
69915
69916 duk_hthread_catchstack_grow(thr);
69917 cat = thr->catchstack + thr->catchstack_top;
69918 thr->catchstack_top++;
69919
69920 cat->flags = DUK_CAT_TYPE_LABEL | (bc << DUK_CAT_LABEL_SHIFT);
69921 cat->callstack_index = thr->callstack_top - 1;
69922 cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */
69923 cat->idx_base = 0; /* unused for label */
69924 cat->h_varname = NULL;
69925
69926 DUK_DDD(DUK_DDDPRINT("LABEL catcher: flags=0x%08lx, callstack_index=%ld, pc_base=%ld, "
69927 "idx_base=%ld, h_varname=%!O, label_id=%ld",
69928 (long) cat->flags, (long) cat->callstack_index, (long) cat->pc_base,
69929 (long) cat->idx_base, (duk_heaphdr *) cat->h_varname, (long) DUK_CAT_GET_LABEL(cat)));
69930
69931 curr_pc += 2; /* skip jump slots */
69932 break;
69933 }
69934
69935 case DUK_EXTRAOP_ENDLABEL: {
69936 duk_catcher *cat;
69937#if defined(DUK_USE_DDDPRINT) || defined(DUK_USE_ASSERTIONS)
69938 duk_uint_fast_t bc = DUK_DEC_BC(ins);
69939#endif
69940#if defined(DUK_USE_DDDPRINT)
69941 DUK_DDD(DUK_DDDPRINT("ENDLABEL %ld", (long) bc));
69942#endif
69943
69944 DUK_ASSERT(thr->catchstack_top >= 1);
69945
69946 cat = thr->catchstack + thr->catchstack_top - 1;
69947 DUK_UNREF(cat);
69948 DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_LABEL);
69949 DUK_ASSERT((duk_uint_fast_t) DUK_CAT_GET_LABEL(cat) == bc);
69950
69951 duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
69952 /* no need to unwind callstack */
69953 break;
69954 }
69955
69956 default: {
69957 DUK__INTERNAL_ERROR("invalid extra opcode");
69958 }
69959
69960 } /* end switch */
69961
69962 break;
69963 }
69964
69965 default: {
69966 /* this should never be possible, because the switch-case is
69967 * comprehensive
69968 */
69969 DUK__INTERNAL_ERROR("invalid opcode");
69970 break;
69971 }
69972
69973 } /* end switch */
69974 }
69975 DUK_UNREACHABLE();
69976
69977#ifndef DUK_USE_VERBOSE_EXECUTOR_ERRORS
69978 internal_error:
11fdf7f2 69979 DUK_ERROR_INTERNAL(thr, "internal error in bytecode executor");
7c673cae
FG
69980#endif
69981}
69982
11fdf7f2
TL
69983#undef DUK__LONGJMP_RESTART
69984#undef DUK__LONGJMP_FINISHED
69985#undef DUK__LONGJMP_RETHROW
69986
69987#undef DUK__RETHAND_RESTART
69988#undef DUK__RETHAND_FINISHED
69989
69990#undef DUK__FUN
69991#undef DUK__STRICT
69992#undef DUK__REG
69993#undef DUK__REGP
69994#undef DUK__CONST
69995#undef DUK__CONSTP
69996#undef DUK__RCISREG
69997#undef DUK__REGCONST
69998#undef DUK__REGCONSTP
69999
7c673cae
FG
70000#undef DUK__INTERNAL_ERROR
70001#undef DUK__SYNC_CURR_PC
70002#undef DUK__SYNC_AND_NULL_CURR_PC
7c673cae
FG
70003/*
70004 * Ecmascript specification algorithm and conversion helpers.
70005 *
70006 * These helpers encapsulate the primitive Ecmascript operation
70007 * semantics, and are used by the bytecode executor and the API
70008 * (among other places). Note that some primitives are only
70009 * implemented as part of the API and have no "internal" helper.
70010 * (This is the case when an internal helper would not really be
70011 * useful; e.g. the operation is rare, uses value stack heavily,
70012 * etc.)
70013 *
70014 * The operation arguments depend on what is required to implement
70015 * the operation:
70016 *
70017 * - If an operation is simple and stateless, and has no side
70018 * effects, it won't take an duk_hthread argument and its
70019 * arguments may be duk_tval pointers (which are safe as long
70020 * as no side effects take place).
70021 *
70022 * - If complex coercions are required (e.g. a "ToNumber" coercion)
70023 * or errors may be thrown, the operation takes an duk_hthread
70024 * argument. This also implies that the operation may have
70025 * arbitrary side effects, invalidating any duk_tval pointers.
70026 *
70027 * - For operations with potential side effects, arguments can be
70028 * taken in several ways:
70029 *
70030 * a) as duk_tval pointers, which makes sense if the "common case"
70031 * can be resolved without side effects (e.g. coercion); the
70032 * arguments are pushed to the valstack for coercion if
70033 * necessary
70034 *
70035 * b) as duk_tval values
70036 *
70037 * c) implicitly on value stack top
70038 *
70039 * d) as indices to the value stack
70040 *
70041 * Future work:
70042 *
70043 * - Argument styles may not be the most sensible in every case now.
70044 *
70045 * - In-place coercions might be useful for several operations, if
70046 * in-place coercion is OK for the bytecode executor and the API.
70047 */
70048
70049/* include removed: duk_internal.h */
70050
70051/*
70052 * [[DefaultValue]] (E5 Section 8.12.8)
70053 *
70054 * ==> implemented in the API.
70055 */
70056
70057/*
70058 * ToPrimitive() (E5 Section 9.1)
70059 *
70060 * ==> implemented in the API.
70061 */
70062
70063/*
70064 * ToBoolean() (E5 Section 9.2)
70065 */
70066
70067DUK_INTERNAL duk_bool_t duk_js_toboolean(duk_tval *tv) {
70068 switch (DUK_TVAL_GET_TAG(tv)) {
70069 case DUK_TAG_UNDEFINED:
70070 case DUK_TAG_NULL:
70071 return 0;
70072 case DUK_TAG_BOOLEAN:
70073 return DUK_TVAL_GET_BOOLEAN(tv);
70074 case DUK_TAG_STRING: {
70075 duk_hstring *h = DUK_TVAL_GET_STRING(tv);
70076 DUK_ASSERT(h != NULL);
70077 return (DUK_HSTRING_GET_BYTELEN(h) > 0 ? 1 : 0);
70078 }
70079 case DUK_TAG_OBJECT: {
70080 return 1;
70081 }
70082 case DUK_TAG_BUFFER: {
70083 /* mimic semantics for strings */
70084 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
70085 DUK_ASSERT(h != NULL);
70086 return (DUK_HBUFFER_GET_SIZE(h) > 0 ? 1 : 0);
70087 }
70088 case DUK_TAG_POINTER: {
70089 void *p = DUK_TVAL_GET_POINTER(tv);
70090 return (p != NULL ? 1 : 0);
70091 }
70092 case DUK_TAG_LIGHTFUNC: {
70093 return 1;
70094 }
70095#if defined(DUK_USE_FASTINT)
70096 case DUK_TAG_FASTINT:
70097 if (DUK_TVAL_GET_FASTINT(tv) != 0) {
70098 return 1;
70099 } else {
70100 return 0;
70101 }
70102#endif
70103 default: {
70104 /* number */
70105 duk_double_t d;
70106 int c;
11fdf7f2 70107 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
7c673cae
FG
70108 DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
70109 d = DUK_TVAL_GET_DOUBLE(tv);
70110 c = DUK_FPCLASSIFY((double) d);
70111 if (c == DUK_FP_ZERO || c == DUK_FP_NAN) {
70112 return 0;
70113 } else {
70114 return 1;
70115 }
70116 }
70117 }
70118 DUK_UNREACHABLE();
70119}
70120
70121/*
70122 * ToNumber() (E5 Section 9.3)
70123 *
70124 * Value to convert must be on stack top, and is popped before exit.
70125 *
70126 * See: http://www.cs.indiana.edu/~burger/FP-Printing-PLDI96.pdf
70127 * http://www.cs.indiana.edu/~burger/fp/index.html
70128 *
70129 * Notes on the conversion:
70130 *
70131 * - There are specific requirements on the accuracy of the conversion
70132 * through a "Mathematical Value" (MV), so this conversion is not
70133 * trivial.
70134 *
70135 * - Quick rejects (e.g. based on first char) are difficult because
70136 * the grammar allows leading and trailing white space.
70137 *
70138 * - Quick reject based on string length is difficult even after
70139 * accounting for white space; there may be arbitrarily many
70140 * decimal digits.
70141 *
70142 * - Standard grammar allows decimal values ("123"), hex values
70143 * ("0x123") and infinities
70144 *
70145 * - Unlike source code literals, ToNumber() coerces empty strings
70146 * and strings with only whitespace to zero (not NaN).
70147 */
70148
70149/* E5 Section 9.3.1 */
70150DUK_LOCAL duk_double_t duk__tonumber_string_raw(duk_hthread *thr) {
70151 duk_context *ctx = (duk_context *) thr;
70152 duk_small_uint_t s2n_flags;
70153 duk_double_t d;
70154
70155 /* Quite lenient, e.g. allow empty as zero, but don't allow trailing
70156 * garbage.
70157 */
70158 s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
70159 DUK_S2N_FLAG_ALLOW_EXP |
70160 DUK_S2N_FLAG_ALLOW_PLUS |
70161 DUK_S2N_FLAG_ALLOW_MINUS |
70162 DUK_S2N_FLAG_ALLOW_INF |
70163 DUK_S2N_FLAG_ALLOW_FRAC |
70164 DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
70165 DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
70166 DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO |
70167 DUK_S2N_FLAG_ALLOW_LEADING_ZERO |
70168 DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT;
70169
70170 duk_numconv_parse(ctx, 10 /*radix*/, s2n_flags);
70171 d = duk_get_number(ctx, -1);
70172 duk_pop(ctx);
70173
70174 return d;
70175}
70176
70177DUK_INTERNAL duk_double_t duk_js_tonumber(duk_hthread *thr, duk_tval *tv) {
70178 duk_context *ctx = (duk_hthread *) thr;
70179
70180 DUK_ASSERT(thr != NULL);
70181 DUK_ASSERT(tv != NULL);
70182
70183 switch (DUK_TVAL_GET_TAG(tv)) {
70184 case DUK_TAG_UNDEFINED: {
70185 /* return a specific NaN (although not strictly necessary) */
70186 duk_double_union du;
70187 DUK_DBLUNION_SET_NAN(&du);
70188 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
70189 return du.d;
70190 }
70191 case DUK_TAG_NULL: {
70192 /* +0.0 */
70193 return 0.0;
70194 }
70195 case DUK_TAG_BOOLEAN: {
70196 if (DUK_TVAL_IS_BOOLEAN_TRUE(tv)) {
70197 return 1.0;
70198 }
70199 return 0.0;
70200 }
70201 case DUK_TAG_STRING: {
70202 duk_hstring *h = DUK_TVAL_GET_STRING(tv);
70203 duk_push_hstring(ctx, h);
70204 return duk__tonumber_string_raw(thr);
70205 }
70206 case DUK_TAG_OBJECT: {
70207 /* Note: ToPrimitive(object,hint) == [[DefaultValue]](object,hint),
70208 * so use [[DefaultValue]] directly.
70209 */
70210 duk_double_t d;
70211 duk_push_tval(ctx, tv);
70212 duk_to_defaultvalue(ctx, -1, DUK_HINT_NUMBER); /* 'tv' becomes invalid */
70213
70214 /* recursive call for a primitive value (guaranteed not to cause second
70215 * recursion).
70216 */
70217 d = duk_js_tonumber(thr, duk_require_tval(ctx, -1));
70218
70219 duk_pop(ctx);
70220 return d;
70221 }
70222 case DUK_TAG_BUFFER: {
70223 /* Coerce like a string. This makes sense because addition also treats
70224 * buffers like strings.
70225 */
70226 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
70227 duk_push_hbuffer(ctx, h);
70228 duk_to_string(ctx, -1); /* XXX: expensive, but numconv now expects to see a string */
70229 return duk__tonumber_string_raw(thr);
70230 }
70231 case DUK_TAG_POINTER: {
70232 /* Coerce like boolean */
70233 void *p = DUK_TVAL_GET_POINTER(tv);
70234 return (p != NULL ? 1.0 : 0.0);
70235 }
70236 case DUK_TAG_LIGHTFUNC: {
70237 /* +(function(){}) -> NaN */
70238 return DUK_DOUBLE_NAN;
70239 }
70240#if defined(DUK_USE_FASTINT)
70241 case DUK_TAG_FASTINT:
70242 return (duk_double_t) DUK_TVAL_GET_FASTINT(tv);
70243#endif
70244 default: {
70245 /* number */
11fdf7f2 70246 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
7c673cae
FG
70247 DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
70248 return DUK_TVAL_GET_DOUBLE(tv);
70249 }
70250 }
70251
70252 DUK_UNREACHABLE();
70253}
70254
70255/*
70256 * ToInteger() (E5 Section 9.4)
70257 */
70258
70259/* exposed, used by e.g. duk_bi_date.c */
70260DUK_INTERNAL duk_double_t duk_js_tointeger_number(duk_double_t x) {
70261 duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x);
70262
70263 if (c == DUK_FP_NAN) {
70264 return 0.0;
70265 } else if (c == DUK_FP_ZERO || c == DUK_FP_INFINITE) {
70266 /* XXX: FP_ZERO check can be removed, the else clause handles it
70267 * correctly (preserving sign).
70268 */
70269 return x;
70270 } else {
70271 duk_small_int_t s = (duk_small_int_t) DUK_SIGNBIT(x);
70272 x = DUK_FLOOR(DUK_FABS(x)); /* truncate towards zero */
70273 if (s) {
70274 x = -x;
70275 }
70276 return x;
70277 }
70278}
70279
70280DUK_INTERNAL duk_double_t duk_js_tointeger(duk_hthread *thr, duk_tval *tv) {
70281 /* XXX: fastint */
70282 duk_double_t d = duk_js_tonumber(thr, tv); /* invalidates tv */
70283 return duk_js_tointeger_number(d);
70284}
70285
70286/*
70287 * ToInt32(), ToUint32(), ToUint16() (E5 Sections 9.5, 9.6, 9.7)
70288 */
70289
70290/* combined algorithm matching E5 Sections 9.5 and 9.6 */
70291DUK_LOCAL duk_double_t duk__toint32_touint32_helper(duk_double_t x, duk_bool_t is_toint32) {
70292 duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x);
70293 duk_small_int_t s;
70294
70295 if (c == DUK_FP_NAN || c == DUK_FP_ZERO || c == DUK_FP_INFINITE) {
70296 return 0.0;
70297 }
70298
70299
70300 /* x = sign(x) * floor(abs(x)), i.e. truncate towards zero, keep sign */
70301 s = (duk_small_int_t) DUK_SIGNBIT(x);
70302 x = DUK_FLOOR(DUK_FABS(x));
70303 if (s) {
70304 x = -x;
70305 }
70306
70307 /* NOTE: fmod(x) result sign is same as sign of x, which
70308 * differs from what Javascript wants (see Section 9.6).
70309 */
70310
70311 x = DUK_FMOD(x, DUK_DOUBLE_2TO32); /* -> x in ]-2**32, 2**32[ */
70312
70313 if (x < 0.0) {
70314 x += DUK_DOUBLE_2TO32;
70315 }
70316 /* -> x in [0, 2**32[ */
70317
70318 if (is_toint32) {
70319 if (x >= DUK_DOUBLE_2TO31) {
70320 /* x in [2**31, 2**32[ */
70321
70322 x -= DUK_DOUBLE_2TO32; /* -> x in [-2**31,2**31[ */
70323 }
70324 }
70325
70326 return x;
70327}
70328
70329DUK_INTERNAL duk_int32_t duk_js_toint32(duk_hthread *thr, duk_tval *tv) {
70330 duk_double_t d;
70331
70332#if defined(DUK_USE_FASTINT)
70333 if (DUK_TVAL_IS_FASTINT(tv)) {
70334 return DUK_TVAL_GET_FASTINT_I32(tv);
70335 }
70336#endif
70337
70338 d = duk_js_tonumber(thr, tv); /* invalidates tv */
70339 d = duk__toint32_touint32_helper(d, 1);
70340 DUK_ASSERT(DUK_FPCLASSIFY(d) == DUK_FP_ZERO || DUK_FPCLASSIFY(d) == DUK_FP_NORMAL);
70341 DUK_ASSERT(d >= -2147483648.0 && d <= 2147483647.0); /* [-0x80000000,0x7fffffff] */
70342 DUK_ASSERT(d == ((duk_double_t) ((duk_int32_t) d))); /* whole, won't clip */
70343 return (duk_int32_t) d;
70344}
70345
70346
70347DUK_INTERNAL duk_uint32_t duk_js_touint32(duk_hthread *thr, duk_tval *tv) {
70348 duk_double_t d;
70349
70350#if defined(DUK_USE_FASTINT)
70351 if (DUK_TVAL_IS_FASTINT(tv)) {
70352 return DUK_TVAL_GET_FASTINT_U32(tv);
70353 }
70354#endif
70355
70356 d = duk_js_tonumber(thr, tv); /* invalidates tv */
70357 d = duk__toint32_touint32_helper(d, 0);
70358 DUK_ASSERT(DUK_FPCLASSIFY(d) == DUK_FP_ZERO || DUK_FPCLASSIFY(d) == DUK_FP_NORMAL);
70359 DUK_ASSERT(d >= 0.0 && d <= 4294967295.0); /* [0x00000000, 0xffffffff] */
70360 DUK_ASSERT(d == ((duk_double_t) ((duk_uint32_t) d))); /* whole, won't clip */
70361 return (duk_uint32_t) d;
70362
70363}
70364
70365DUK_INTERNAL duk_uint16_t duk_js_touint16(duk_hthread *thr, duk_tval *tv) {
70366 /* should be a safe way to compute this */
70367 return (duk_uint16_t) (duk_js_touint32(thr, tv) & 0x0000ffffU);
70368}
70369
70370/*
70371 * ToString() (E5 Section 9.8)
70372 *
70373 * ==> implemented in the API.
70374 */
70375
70376/*
70377 * ToObject() (E5 Section 9.9)
70378 *
70379 * ==> implemented in the API.
70380 */
70381
70382/*
70383 * CheckObjectCoercible() (E5 Section 9.10)
70384 *
70385 * Note: no API equivalent now.
70386 */
70387
70388#if 0 /* unused */
70389DUK_INTERNAL void duk_js_checkobjectcoercible(duk_hthread *thr, duk_tval *tv_x) {
70390 duk_small_uint_t tag = DUK_TVAL_GET_TAG(tv_x);
70391
70392 /* Note: this must match ToObject() behavior */
70393
70394 if (tag == DUK_TAG_UNDEFINED ||
70395 tag == DUK_TAG_NULL ||
70396 tag == DUK_TAG_POINTER ||
70397 tag == DUK_TAG_BUFFER) {
11fdf7f2 70398 DUK_ERROR_TYPE(thr, "not object coercible");
7c673cae
FG
70399 }
70400}
70401#endif
70402
70403/*
70404 * IsCallable() (E5 Section 9.11)
70405 *
70406 * XXX: API equivalent is a separate implementation now, and this has
70407 * currently no callers.
70408 */
70409
70410#if 0 /* unused */
70411DUK_INTERNAL duk_bool_t duk_js_iscallable(duk_tval *tv_x) {
70412 duk_hobject *obj;
70413
70414 if (!DUK_TVAL_IS_OBJECT(tv_x)) {
70415 return 0;
70416 }
70417 obj = DUK_TVAL_GET_OBJECT(tv_x);
70418 DUK_ASSERT(obj != NULL);
70419
70420 return DUK_HOBJECT_IS_CALLABLE(obj);
70421}
70422#endif
70423
70424/*
70425 * Loose equality, strict equality, and SameValue (E5 Sections 11.9.1, 11.9.4,
70426 * 9.12). These have much in common so they can share some helpers.
70427 *
70428 * Future work notes:
70429 *
70430 * - Current implementation (and spec definition) has recursion; this should
70431 * be fixed if possible.
70432 *
70433 * - String-to-number coercion should be possible without going through the
70434 * value stack (and be more compact) if a shared helper is invoked.
70435 */
70436
70437/* Note that this is the same operation for strict and loose equality:
70438 * - E5 Section 11.9.3, step 1.c (loose)
70439 * - E5 Section 11.9.6, step 4 (strict)
70440 */
70441
70442DUK_LOCAL duk_bool_t duk__js_equals_number(duk_double_t x, duk_double_t y) {
70443#if defined(DUK_USE_PARANOID_MATH)
70444 /* Straightforward algorithm, makes fewer compiler assumptions. */
70445 duk_small_int_t cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
70446 duk_small_int_t cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
70447 if (cx == DUK_FP_NAN || cy == DUK_FP_NAN) {
70448 return 0;
70449 }
70450 if (cx == DUK_FP_ZERO && cy == DUK_FP_ZERO) {
70451 return 1;
70452 }
70453 if (x == y) {
70454 return 1;
70455 }
70456 return 0;
70457#else /* DUK_USE_PARANOID_MATH */
70458 /* Better equivalent algorithm. If the compiler is compliant, C and
70459 * Ecmascript semantics are identical for this particular comparison.
70460 * In particular, NaNs must never compare equal and zeroes must compare
70461 * equal regardless of sign. Could also use a macro, but this inlines
70462 * already nicely (no difference on gcc, for instance).
70463 */
70464 if (x == y) {
70465 /* IEEE requires that NaNs compare false */
70466 DUK_ASSERT(DUK_FPCLASSIFY(x) != DUK_FP_NAN);
70467 DUK_ASSERT(DUK_FPCLASSIFY(y) != DUK_FP_NAN);
70468 return 1;
70469 } else {
70470 /* IEEE requires that zeros compare the same regardless
70471 * of their signed, so if both x and y are zeroes, they
70472 * are caught above.
70473 */
70474 DUK_ASSERT(!(DUK_FPCLASSIFY(x) == DUK_FP_ZERO && DUK_FPCLASSIFY(y) == DUK_FP_ZERO));
70475 return 0;
70476 }
70477#endif /* DUK_USE_PARANOID_MATH */
70478}
70479
70480DUK_LOCAL duk_bool_t duk__js_samevalue_number(duk_double_t x, duk_double_t y) {
70481#if defined(DUK_USE_PARANOID_MATH)
70482 duk_small_int_t cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
70483 duk_small_int_t cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
70484
70485 if (cx == DUK_FP_NAN && cy == DUK_FP_NAN) {
70486 /* SameValue(NaN, NaN) = true, regardless of NaN sign or extra bits */
70487 return 1;
70488 }
70489 if (cx == DUK_FP_ZERO && cy == DUK_FP_ZERO) {
70490 /* Note: cannot assume that a non-zero return value of signbit() would
70491 * always be the same -- hence cannot (portably) use something like:
70492 *
70493 * signbit(x) == signbit(y)
70494 */
70495 duk_small_int_t sx = (DUK_SIGNBIT(x) ? 1 : 0);
70496 duk_small_int_t sy = (DUK_SIGNBIT(y) ? 1 : 0);
70497 return (sx == sy);
70498 }
70499
70500 /* normal comparison; known:
70501 * - both x and y are not NaNs (but one of them can be)
70502 * - both x and y are not zero (but one of them can be)
70503 * - x and y may be denormal or infinite
70504 */
70505
70506 return (x == y);
70507#else /* DUK_USE_PARANOID_MATH */
70508 duk_small_int_t cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
70509 duk_small_int_t cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
70510
70511 if (x == y) {
70512 /* IEEE requires that NaNs compare false */
70513 DUK_ASSERT(DUK_FPCLASSIFY(x) != DUK_FP_NAN);
70514 DUK_ASSERT(DUK_FPCLASSIFY(y) != DUK_FP_NAN);
70515
70516 /* Using classification has smaller footprint than direct comparison. */
70517 if (DUK_UNLIKELY(cx == DUK_FP_ZERO && cy == DUK_FP_ZERO)) {
70518 /* Note: cannot assume that a non-zero return value of signbit() would
70519 * always be the same -- hence cannot (portably) use something like:
70520 *
70521 * signbit(x) == signbit(y)
70522 */
70523 duk_small_int_t sx = (DUK_SIGNBIT(x) ? 1 : 0);
70524 duk_small_int_t sy = (DUK_SIGNBIT(y) ? 1 : 0);
70525 return (sx == sy);
70526 }
70527 return 1;
70528 } else {
70529 /* IEEE requires that zeros compare the same regardless
70530 * of their signed, so if both x and y are zeroes, they
70531 * are caught above.
70532 */
70533 DUK_ASSERT(!(DUK_FPCLASSIFY(x) == DUK_FP_ZERO && DUK_FPCLASSIFY(y) == DUK_FP_ZERO));
70534
70535 /* Difference to non-strict/strict comparison is that NaNs compare
70536 * equal and signed zero signs matter.
70537 */
70538 if (DUK_UNLIKELY(cx == DUK_FP_NAN && cy == DUK_FP_NAN)) {
70539 /* SameValue(NaN, NaN) = true, regardless of NaN sign or extra bits */
70540 return 1;
70541 }
70542 return 0;
70543 }
70544#endif /* DUK_USE_PARANOID_MATH */
70545}
70546
70547DUK_INTERNAL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags) {
70548 duk_context *ctx = (duk_context *) thr;
70549 duk_tval *tv_tmp;
70550
70551 /* If flags != 0 (strict or SameValue), thr can be NULL. For loose
70552 * equals comparison it must be != NULL.
70553 */
70554 DUK_ASSERT(flags != 0 || thr != NULL);
70555
70556 /*
70557 * Same type?
70558 *
70559 * Note: since number values have no explicit tag in the 8-byte
70560 * representation, need the awkward if + switch.
70561 */
70562
70563#if defined(DUK_USE_FASTINT)
70564 if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
70565 if (DUK_TVAL_GET_FASTINT(tv_x) == DUK_TVAL_GET_FASTINT(tv_y)) {
70566 return 1;
70567 } else {
70568 return 0;
70569 }
70570 }
70571 else
70572#endif
70573 if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
70574 /* Catches both doubles and cases where only one argument is a fastint */
70575 if (DUK_UNLIKELY((flags & DUK_EQUALS_FLAG_SAMEVALUE) != 0)) {
70576 /* SameValue */
70577 return duk__js_samevalue_number(DUK_TVAL_GET_NUMBER(tv_x),
70578 DUK_TVAL_GET_NUMBER(tv_y));
70579 } else {
70580 /* equals and strict equals */
70581 return duk__js_equals_number(DUK_TVAL_GET_NUMBER(tv_x),
70582 DUK_TVAL_GET_NUMBER(tv_y));
70583 }
70584 } else if (DUK_TVAL_GET_TAG(tv_x) == DUK_TVAL_GET_TAG(tv_y)) {
70585 switch (DUK_TVAL_GET_TAG(tv_x)) {
70586 case DUK_TAG_UNDEFINED:
70587 case DUK_TAG_NULL: {
70588 return 1;
70589 }
70590 case DUK_TAG_BOOLEAN: {
70591 return DUK_TVAL_GET_BOOLEAN(tv_x) == DUK_TVAL_GET_BOOLEAN(tv_y);
70592 }
70593 case DUK_TAG_POINTER: {
70594 return DUK_TVAL_GET_POINTER(tv_x) == DUK_TVAL_GET_POINTER(tv_y);
70595 }
70596 case DUK_TAG_STRING:
70597 case DUK_TAG_OBJECT: {
70598 /* heap pointer comparison suffices */
70599 return DUK_TVAL_GET_HEAPHDR(tv_x) == DUK_TVAL_GET_HEAPHDR(tv_y);
70600 }
70601 case DUK_TAG_BUFFER: {
70602 if ((flags & (DUK_EQUALS_FLAG_STRICT | DUK_EQUALS_FLAG_SAMEVALUE)) != 0) {
70603 /* heap pointer comparison suffices */
70604 return DUK_TVAL_GET_HEAPHDR(tv_x) == DUK_TVAL_GET_HEAPHDR(tv_y);
70605 } else {
70606 /* non-strict equality for buffers compares contents */
70607 duk_hbuffer *h_x = DUK_TVAL_GET_BUFFER(tv_x);
70608 duk_hbuffer *h_y = DUK_TVAL_GET_BUFFER(tv_y);
70609 duk_size_t len_x = DUK_HBUFFER_GET_SIZE(h_x);
70610 duk_size_t len_y = DUK_HBUFFER_GET_SIZE(h_y);
70611 void *buf_x;
70612 void *buf_y;
70613 if (len_x != len_y) {
70614 return 0;
70615 }
70616 buf_x = (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_x);
70617 buf_y = (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_y);
70618 /* if len_x == len_y == 0, buf_x and/or buf_y may
70619 * be NULL, but that's OK.
70620 */
70621 DUK_ASSERT(len_x == len_y);
70622 DUK_ASSERT(len_x == 0 || buf_x != NULL);
70623 DUK_ASSERT(len_y == 0 || buf_y != NULL);
11fdf7f2 70624 return (DUK_MEMCMP((const void *) buf_x, (const void *) buf_y, (size_t) len_x) == 0) ? 1 : 0;
7c673cae
FG
70625 }
70626 }
70627 case DUK_TAG_LIGHTFUNC: {
70628 /* At least 'magic' has a significant impact on function
70629 * identity.
70630 */
70631 duk_small_uint_t lf_flags_x;
70632 duk_small_uint_t lf_flags_y;
70633 duk_c_function func_x;
70634 duk_c_function func_y;
70635
70636 DUK_TVAL_GET_LIGHTFUNC(tv_x, func_x, lf_flags_x);
70637 DUK_TVAL_GET_LIGHTFUNC(tv_y, func_y, lf_flags_y);
70638 return ((func_x == func_y) && (lf_flags_x == lf_flags_y)) ? 1 : 0;
70639 }
70640#if defined(DUK_USE_FASTINT)
70641 case DUK_TAG_FASTINT:
70642#endif
70643 default: {
11fdf7f2
TL
70644 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_x));
70645 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_y));
7c673cae
FG
70646 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_x));
70647 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_y));
70648 DUK_UNREACHABLE();
70649 return 0;
70650 }
70651 }
70652 }
70653
70654 if ((flags & (DUK_EQUALS_FLAG_STRICT | DUK_EQUALS_FLAG_SAMEVALUE)) != 0) {
70655 return 0;
70656 }
70657
70658 DUK_ASSERT(flags == 0); /* non-strict equality from here on */
70659
70660 /*
70661 * Types are different; various cases for non-strict comparison
70662 *
70663 * Since comparison is symmetric, we use a "swap trick" to reduce
70664 * code size.
70665 */
70666
70667 /* Undefined/null are considered equal (e.g. "null == undefined" -> true). */
70668 if ((DUK_TVAL_IS_UNDEFINED(tv_x) && DUK_TVAL_IS_NULL(tv_y)) ||
70669 (DUK_TVAL_IS_NULL(tv_x) && DUK_TVAL_IS_UNDEFINED(tv_y))) {
70670 return 1;
70671 }
70672
70673 /* Number/string-or-buffer -> coerce string to number (e.g. "'1.5' == 1.5" -> true). */
70674 if (DUK_TVAL_IS_NUMBER(tv_x) && (DUK_TVAL_IS_STRING(tv_y) || DUK_TVAL_IS_BUFFER(tv_y))) {
70675 /* the next 'if' is guaranteed to match after swap */
70676 tv_tmp = tv_x;
70677 tv_x = tv_y;
70678 tv_y = tv_tmp;
70679 }
70680 if ((DUK_TVAL_IS_STRING(tv_x) || DUK_TVAL_IS_BUFFER(tv_x)) && DUK_TVAL_IS_NUMBER(tv_y)) {
70681 /* XXX: this is possible without resorting to the value stack */
70682 duk_double_t d1, d2;
70683 d2 = DUK_TVAL_GET_NUMBER(tv_y);
70684 duk_push_tval(ctx, tv_x);
70685 duk_to_string(ctx, -1); /* buffer values are coerced first to string here */
70686 duk_to_number(ctx, -1);
70687 d1 = duk_require_number(ctx, -1);
70688 duk_pop(ctx);
70689 return duk__js_equals_number(d1, d2);
70690 }
70691
70692 /* Buffer/string -> compare contents. */
70693 if (DUK_TVAL_IS_BUFFER(tv_x) && DUK_TVAL_IS_STRING(tv_y)) {
70694 tv_tmp = tv_x;
70695 tv_x = tv_y;
70696 tv_y = tv_tmp;
70697 }
70698 if (DUK_TVAL_IS_STRING(tv_x) && DUK_TVAL_IS_BUFFER(tv_y)) {
70699 duk_hstring *h_x = DUK_TVAL_GET_STRING(tv_x);
70700 duk_hbuffer *h_y = DUK_TVAL_GET_BUFFER(tv_y);
70701 duk_size_t len_x = DUK_HSTRING_GET_BYTELEN(h_x);
70702 duk_size_t len_y = DUK_HBUFFER_GET_SIZE(h_y);
11fdf7f2
TL
70703 const void *buf_x;
70704 const void *buf_y;
7c673cae
FG
70705 if (len_x != len_y) {
70706 return 0;
70707 }
11fdf7f2
TL
70708 buf_x = (const void *) DUK_HSTRING_GET_DATA(h_x);
70709 buf_y = (const void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_y);
7c673cae
FG
70710 /* if len_x == len_y == 0, buf_x and/or buf_y may
70711 * be NULL, but that's OK.
70712 */
70713 DUK_ASSERT(len_x == len_y);
70714 DUK_ASSERT(len_x == 0 || buf_x != NULL);
70715 DUK_ASSERT(len_y == 0 || buf_y != NULL);
11fdf7f2 70716 return (DUK_MEMCMP((const void *) buf_x, (const void *) buf_y, (size_t) len_x) == 0) ? 1 : 0;
7c673cae
FG
70717 }
70718
70719 /* Boolean/any -> coerce boolean to number and try again. If boolean is
70720 * compared to a pointer, the final comparison after coercion now always
70721 * yields false (as pointer vs. number compares to false), but this is
70722 * not special cased.
70723 */
70724 if (DUK_TVAL_IS_BOOLEAN(tv_x)) {
70725 tv_tmp = tv_x;
70726 tv_x = tv_y;
70727 tv_y = tv_tmp;
70728 }
70729 if (DUK_TVAL_IS_BOOLEAN(tv_y)) {
70730 /* ToNumber(bool) is +1.0 or 0.0. Tagged boolean value is always 0 or 1. */
70731 duk_bool_t rc;
70732 DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv_y) == 0 || DUK_TVAL_GET_BOOLEAN(tv_y) == 1);
70733 duk_push_tval(ctx, tv_x);
70734 duk_push_int(ctx, DUK_TVAL_GET_BOOLEAN(tv_y));
11fdf7f2
TL
70735 rc = duk_js_equals_helper(thr,
70736 DUK_GET_TVAL_NEGIDX(ctx, -2),
70737 DUK_GET_TVAL_NEGIDX(ctx, -1),
70738 0 /*flags:nonstrict*/);
7c673cae
FG
70739 duk_pop_2(ctx);
70740 return rc;
70741 }
70742
70743 /* String-number-buffer/object -> coerce object to primitive (apparently without hint), then try again. */
70744 if ((DUK_TVAL_IS_STRING(tv_x) || DUK_TVAL_IS_NUMBER(tv_x) || DUK_TVAL_IS_BUFFER(tv_x)) &&
70745 DUK_TVAL_IS_OBJECT(tv_y)) {
70746 tv_tmp = tv_x;
70747 tv_x = tv_y;
70748 tv_y = tv_tmp;
70749 }
70750 if (DUK_TVAL_IS_OBJECT(tv_x) &&
70751 (DUK_TVAL_IS_STRING(tv_y) || DUK_TVAL_IS_NUMBER(tv_y) || DUK_TVAL_IS_BUFFER(tv_y))) {
70752 duk_bool_t rc;
70753 duk_push_tval(ctx, tv_x);
70754 duk_push_tval(ctx, tv_y);
70755 duk_to_primitive(ctx, -2, DUK_HINT_NONE); /* apparently no hint? */
11fdf7f2
TL
70756 rc = duk_js_equals_helper(thr,
70757 DUK_GET_TVAL_NEGIDX(ctx, -2),
70758 DUK_GET_TVAL_NEGIDX(ctx, -1),
70759 0 /*flags:nonstrict*/);
7c673cae
FG
70760 duk_pop_2(ctx);
70761 return rc;
70762 }
70763
70764 /* Nothing worked -> not equal. */
70765 return 0;
70766}
70767
70768/*
70769 * Comparisons (x >= y, x > y, x <= y, x < y)
70770 *
70771 * E5 Section 11.8.5: implement 'x < y' and then use negate and eval_left_first
70772 * flags to get the rest.
70773 */
70774
70775/* XXX: this should probably just operate on the stack top, because it
70776 * needs to push stuff on the stack anyway...
70777 */
70778
70779DUK_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) {
70780 duk_size_t prefix_len;
70781 duk_small_int_t rc;
70782
70783 prefix_len = (len1 <= len2 ? len1 : len2);
70784
11fdf7f2
TL
70785 /* DUK_MEMCMP() is guaranteed to return zero (equal) for zero length
70786 * inputs so no zero length check is needed.
7c673cae 70787 */
11fdf7f2
TL
70788 rc = DUK_MEMCMP((const void *) buf1,
70789 (const void *) buf2,
70790 (size_t) prefix_len);
7c673cae
FG
70791
70792 if (rc < 0) {
70793 return -1;
70794 } else if (rc > 0) {
70795 return 1;
70796 }
70797
70798 /* prefix matches, lengths matter now */
70799 if (len1 < len2) {
70800 /* e.g. "x" < "xx" */
70801 return -1;
70802 } else if (len1 > len2) {
70803 return 1;
70804 }
70805
70806 return 0;
70807}
70808
70809DUK_INTERNAL duk_small_int_t duk_js_string_compare(duk_hstring *h1, duk_hstring *h2) {
70810 /*
70811 * String comparison (E5 Section 11.8.5, step 4), which
70812 * needs to compare codepoint by codepoint.
70813 *
70814 * However, UTF-8 allows us to use strcmp directly: the shared
70815 * prefix will be encoded identically (UTF-8 has unique encoding)
70816 * and the first differing character can be compared with a simple
70817 * unsigned byte comparison (which strcmp does).
70818 *
70819 * This will not work properly for non-xutf-8 strings, but this
70820 * is not an issue for compliance.
70821 */
70822
70823 DUK_ASSERT(h1 != NULL);
70824 DUK_ASSERT(h2 != NULL);
70825
70826 return duk_js_data_compare((const duk_uint8_t *) DUK_HSTRING_GET_DATA(h1),
70827 (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h2),
70828 (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1),
70829 (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2));
70830}
70831
70832#if 0 /* unused */
70833DUK_INTERNAL duk_small_int_t duk_js_buffer_compare(duk_heap *heap, duk_hbuffer *h1, duk_hbuffer *h2) {
70834 /* Similar to String comparison. */
70835
70836 DUK_ASSERT(h1 != NULL);
70837 DUK_ASSERT(h2 != NULL);
70838 DUK_UNREF(heap);
70839
70840 return duk_js_data_compare((const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(heap, h1),
70841 (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(heap, h2),
70842 (duk_size_t) DUK_HBUFFER_GET_SIZE(h1),
70843 (duk_size_t) DUK_HBUFFER_GET_SIZE(h2));
70844}
70845#endif
70846
70847DUK_INTERNAL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags) {
70848 duk_context *ctx = (duk_context *) thr;
70849 duk_double_t d1, d2;
70850 duk_small_int_t c1, c2;
70851 duk_small_int_t s1, s2;
70852 duk_small_int_t rc;
70853 duk_bool_t retval;
70854
70855 /* Fast path for fastints */
70856#if defined(DUK_USE_FASTINT)
70857 if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
70858 duk_int64_t v1 = DUK_TVAL_GET_FASTINT(tv_x);
70859 duk_int64_t v2 = DUK_TVAL_GET_FASTINT(tv_y);
70860 if (v1 < v2) {
70861 /* 'lt is true' */
70862 retval = 1;
70863 } else {
70864 retval = 0;
70865 }
70866 if (flags & DUK_COMPARE_FLAG_NEGATE) {
70867 retval ^= 1;
70868 }
70869 return retval;
70870 }
70871#endif /* DUK_USE_FASTINT */
70872
70873 /* Fast path for numbers (one of which may be a fastint) */
70874#if 1 /* XXX: make fast paths optional for size minimization? */
70875 if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
70876 d1 = DUK_TVAL_GET_NUMBER(tv_x);
70877 d2 = DUK_TVAL_GET_NUMBER(tv_y);
70878 c1 = DUK_FPCLASSIFY(d1);
70879 c2 = DUK_FPCLASSIFY(d2);
70880
70881 if (c1 == DUK_FP_NORMAL && c2 == DUK_FP_NORMAL) {
70882 /* XXX: this is a very narrow check, and doesn't cover
70883 * zeroes, subnormals, infinities, which compare normally.
70884 */
70885
70886 if (d1 < d2) {
70887 /* 'lt is true' */
70888 retval = 1;
70889 } else {
70890 retval = 0;
70891 }
70892 if (flags & DUK_COMPARE_FLAG_NEGATE) {
70893 retval ^= 1;
70894 }
70895 return retval;
70896 }
70897 }
70898#endif
70899
70900 /* Slow path */
70901
70902 duk_push_tval(ctx, tv_x);
70903 duk_push_tval(ctx, tv_y);
70904
70905 if (flags & DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) {
70906 duk_to_primitive(ctx, -2, DUK_HINT_NUMBER);
70907 duk_to_primitive(ctx, -1, DUK_HINT_NUMBER);
70908 } else {
70909 duk_to_primitive(ctx, -1, DUK_HINT_NUMBER);
70910 duk_to_primitive(ctx, -2, DUK_HINT_NUMBER);
70911 }
70912
70913 /* Note: reuse variables */
11fdf7f2
TL
70914 tv_x = DUK_GET_TVAL_NEGIDX(ctx, -2);
70915 tv_y = DUK_GET_TVAL_NEGIDX(ctx, -1);
7c673cae
FG
70916
70917 if (DUK_TVAL_IS_STRING(tv_x) && DUK_TVAL_IS_STRING(tv_y)) {
70918 duk_hstring *h1 = DUK_TVAL_GET_STRING(tv_x);
70919 duk_hstring *h2 = DUK_TVAL_GET_STRING(tv_y);
70920 DUK_ASSERT(h1 != NULL);
70921 DUK_ASSERT(h2 != NULL);
70922
70923 rc = duk_js_string_compare(h1, h2);
70924 if (rc < 0) {
70925 goto lt_true;
70926 } else {
70927 goto lt_false;
70928 }
70929 } else {
70930 /* Ordering should not matter (E5 Section 11.8.5, step 3.a) but
70931 * preserve it just in case.
70932 */
70933
70934 if (flags & DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) {
70935 d1 = duk_to_number(ctx, -2);
70936 d2 = duk_to_number(ctx, -1);
70937 } else {
70938 d2 = duk_to_number(ctx, -1);
70939 d1 = duk_to_number(ctx, -2);
70940 }
70941
70942 c1 = (duk_small_int_t) DUK_FPCLASSIFY(d1);
70943 s1 = (duk_small_int_t) DUK_SIGNBIT(d1);
70944 c2 = (duk_small_int_t) DUK_FPCLASSIFY(d2);
70945 s2 = (duk_small_int_t) DUK_SIGNBIT(d2);
70946
70947 if (c1 == DUK_FP_NAN || c2 == DUK_FP_NAN) {
70948 goto lt_undefined;
70949 }
70950
70951 if (c1 == DUK_FP_ZERO && c2 == DUK_FP_ZERO) {
70952 /* For all combinations: +0 < +0, +0 < -0, -0 < +0, -0 < -0,
70953 * steps e, f, and g.
70954 */
70955 goto lt_false;
70956 }
70957
70958 if (d1 == d2) {
70959 goto lt_false;
70960 }
70961
70962 if (c1 == DUK_FP_INFINITE && s1 == 0) {
70963 /* x == +Infinity */
70964 goto lt_false;
70965 }
70966
70967 if (c2 == DUK_FP_INFINITE && s2 == 0) {
70968 /* y == +Infinity */
70969 goto lt_true;
70970 }
70971
70972 if (c2 == DUK_FP_INFINITE && s2 != 0) {
70973 /* y == -Infinity */
70974 goto lt_false;
70975 }
70976
70977 if (c1 == DUK_FP_INFINITE && s1 != 0) {
70978 /* x == -Infinity */
70979 goto lt_true;
70980 }
70981
70982 if (d1 < d2) {
70983 goto lt_true;
70984 }
70985
70986 goto lt_false;
70987 }
70988
70989 lt_undefined:
70990 /* Note: undefined from Section 11.8.5 always results in false
70991 * return (see e.g. Section 11.8.3) - hence special treatment here.
70992 */
70993 retval = 0;
70994 goto cleanup;
70995
70996 lt_true:
70997 if (flags & DUK_COMPARE_FLAG_NEGATE) {
70998 retval = 0;
70999 goto cleanup;
71000 } else {
71001 retval = 1;
71002 goto cleanup;
71003 }
71004 /* never here */
71005
71006 lt_false:
71007 if (flags & DUK_COMPARE_FLAG_NEGATE) {
71008 retval = 1;
71009 goto cleanup;
71010 } else {
71011 retval = 0;
71012 goto cleanup;
71013 }
71014 /* never here */
71015
71016 cleanup:
71017 duk_pop_2(ctx);
71018 return retval;
71019}
71020
71021/*
71022 * instanceof
71023 */
71024
71025/*
71026 * E5 Section 11.8.6 describes the main algorithm, which uses
71027 * [[HasInstance]]. [[HasInstance]] is defined for only
71028 * function objects:
71029 *
71030 * - Normal functions:
71031 * E5 Section 15.3.5.3
71032 * - Functions established with Function.prototype.bind():
71033 * E5 Section 15.3.4.5.3
71034 *
71035 * For other objects, a TypeError is thrown.
71036 *
71037 * Limited Proxy support: don't support 'getPrototypeOf' trap but
71038 * continue lookup in Proxy target if the value is a Proxy.
71039 */
71040
71041DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
71042 duk_context *ctx = (duk_context *) thr;
71043 duk_hobject *func;
71044 duk_hobject *val;
71045 duk_hobject *proto;
71046 duk_uint_t sanity;
71047
71048 /*
71049 * Get the values onto the stack first. It would be possible to cover
71050 * some normal cases without resorting to the value stack.
71051 *
71052 * The right hand side could be a light function (as they generally
71053 * behave like objects). Light functions never have a 'prototype'
71054 * property so E5.1 Section 15.3.5.3 step 3 always throws a TypeError.
71055 * Using duk_require_hobject() is thus correct (except for error msg).
71056 */
71057
71058 duk_push_tval(ctx, tv_x);
71059 duk_push_tval(ctx, tv_y);
71060 func = duk_require_hobject(ctx, -1);
71061
71062 /*
71063 * For bound objects, [[HasInstance]] just calls the target function
71064 * [[HasInstance]]. If that is again a bound object, repeat until
71065 * we find a non-bound Function object.
71066 */
71067
71068 /* XXX: this bound function resolution also happens elsewhere,
71069 * move into a shared helper.
71070 */
71071
71072 sanity = DUK_HOBJECT_BOUND_CHAIN_SANITY;
71073 do {
71074 /* check func supports [[HasInstance]] (this is checked for every function
71075 * in the bound chain, including the final one)
71076 */
71077
71078 if (!DUK_HOBJECT_IS_CALLABLE(func)) {
71079 /*
71080 * Note: of native Ecmascript objects, only Function instances
71081 * have a [[HasInstance]] internal property. Custom objects might
71082 * also have it, but not in current implementation.
71083 *
71084 * XXX: add a separate flag, DUK_HOBJECT_FLAG_ALLOW_INSTANCEOF?
71085 */
11fdf7f2 71086 DUK_ERROR_TYPE(thr, "invalid instanceof rval");
7c673cae
FG
71087 }
71088
71089 if (!DUK_HOBJECT_HAS_BOUND(func)) {
71090 break;
71091 }
71092
71093 /* [ ... lval rval ] */
71094
71095 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TARGET); /* -> [ ... lval rval new_rval ] */
71096 duk_replace(ctx, -1); /* -> [ ... lval new_rval ] */
71097 func = duk_require_hobject(ctx, -1);
71098
71099 /* func support for [[HasInstance]] checked in the beginning of the loop */
71100 } while (--sanity > 0);
71101
71102 if (sanity == 0) {
11fdf7f2 71103 DUK_ERROR_RANGE(thr, DUK_STR_BOUND_CHAIN_LIMIT);
7c673cae
FG
71104 }
71105
71106 /*
71107 * 'func' is now a non-bound object which supports [[HasInstance]]
71108 * (which here just means DUK_HOBJECT_FLAG_CALLABLE). Move on
71109 * to execute E5 Section 15.3.5.3.
71110 */
71111
71112 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
71113 DUK_ASSERT(DUK_HOBJECT_IS_CALLABLE(func));
71114
71115 /* [ ... lval rval(func) ] */
71116
71117 /* Handle lightfuncs through object coercion for now. */
71118 /* XXX: direct implementation */
71119 val = duk_get_hobject_or_lfunc_coerce(ctx, -2);
71120 if (!val) {
71121 goto pop_and_false;
71122 }
71123
71124 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_PROTOTYPE); /* -> [ ... lval rval rval.prototype ] */
71125 proto = duk_require_hobject(ctx, -1);
71126 duk_pop(ctx); /* -> [ ... lval rval ] */
71127
71128 DUK_ASSERT(val != NULL);
71129
71130#if defined(DUK_USE_ES6_PROXY)
71131 val = duk_hobject_resolve_proxy_target(thr, val);
71132 DUK_ASSERT(val != NULL);
71133#endif
71134
71135 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
71136 do {
71137 /*
71138 * Note: prototype chain is followed BEFORE first comparison. This
71139 * means that the instanceof lval is never itself compared to the
71140 * rval.prototype property. This is apparently intentional, see E5
71141 * Section 15.3.5.3, step 4.a.
71142 *
71143 * Also note:
71144 *
71145 * js> (function() {}) instanceof Function
71146 * true
71147 * js> Function instanceof Function
71148 * true
71149 *
71150 * For the latter, h_proto will be Function.prototype, which is the
71151 * built-in Function prototype. Because Function.[[Prototype]] is
71152 * also the built-in Function prototype, the result is true.
71153 */
71154
71155 DUK_ASSERT(val != NULL);
71156 val = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, val);
71157
71158 if (!val) {
71159 goto pop_and_false;
71160 }
71161
71162 DUK_ASSERT(val != NULL);
71163#if defined(DUK_USE_ES6_PROXY)
71164 val = duk_hobject_resolve_proxy_target(thr, val);
71165#endif
71166
71167 if (val == proto) {
71168 goto pop_and_true;
71169 }
71170
71171 /* follow prototype chain */
71172 } while (--sanity > 0);
71173
71174 if (sanity == 0) {
11fdf7f2 71175 DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
7c673cae
FG
71176 }
71177 DUK_UNREACHABLE();
71178
71179 pop_and_false:
71180 duk_pop_2(ctx);
71181 return 0;
71182
71183 pop_and_true:
71184 duk_pop_2(ctx);
71185 return 1;
71186}
71187
71188/*
71189 * in
71190 */
71191
71192/*
71193 * E5 Sections 11.8.7, 8.12.6.
71194 *
71195 * Basically just a property existence check using [[HasProperty]].
71196 */
71197
71198DUK_INTERNAL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
71199 duk_context *ctx = (duk_context *) thr;
71200 duk_bool_t retval;
71201
71202 /*
71203 * Get the values onto the stack first. It would be possible to cover
71204 * some normal cases without resorting to the value stack (e.g. if
71205 * lval is already a string).
71206 */
71207
71208 /* XXX: The ES5/5.1/6 specifications require that the key in 'key in obj'
71209 * must be string coerced before the internal HasProperty() algorithm is
71210 * invoked. A fast path skipping coercion could be safely implemented for
71211 * numbers (as number-to-string coercion has no side effects). For ES6
71212 * proxy behavior, the trap 'key' argument must be in a string coerced
71213 * form (which is a shame).
71214 */
71215
71216 /* TypeError if rval is not an object (or lightfunc which should behave
71217 * like a Function instance).
71218 */
71219 duk_push_tval(ctx, tv_x);
71220 duk_push_tval(ctx, tv_y);
71221 duk_require_type_mask(ctx, -1, DUK_TYPE_MASK_OBJECT | DUK_TYPE_MASK_LIGHTFUNC);
71222 duk_to_string(ctx, -2); /* coerce lval with ToString() */
71223
11fdf7f2
TL
71224 retval = duk_hobject_hasprop(thr,
71225 DUK_GET_TVAL_NEGIDX(ctx, -1),
71226 DUK_GET_TVAL_NEGIDX(ctx, -2));
7c673cae
FG
71227
71228 duk_pop_2(ctx);
71229 return retval;
71230}
71231
71232/*
71233 * typeof
71234 *
71235 * E5 Section 11.4.3.
71236 *
71237 * Very straightforward. The only question is what to return for our
71238 * non-standard tag / object types.
71239 *
71240 * There is an unfortunate string constant define naming problem with
71241 * typeof return values for e.g. "Object" and "object"; careful with
71242 * the built-in string defines. The LC_XXX defines are used for the
71243 * lowercase variants now.
71244 */
71245
71246DUK_INTERNAL duk_hstring *duk_js_typeof(duk_hthread *thr, duk_tval *tv_x) {
71247 duk_small_int_t stridx = 0;
71248
11fdf7f2
TL
71249 DUK_UNREF(thr);
71250
7c673cae
FG
71251 switch (DUK_TVAL_GET_TAG(tv_x)) {
71252 case DUK_TAG_UNDEFINED: {
71253 stridx = DUK_STRIDX_LC_UNDEFINED;
71254 break;
71255 }
71256 case DUK_TAG_NULL: {
71257 /* Note: not a typo, "object" is returned for a null value */
71258 stridx = DUK_STRIDX_LC_OBJECT;
71259 break;
71260 }
71261 case DUK_TAG_BOOLEAN: {
71262 stridx = DUK_STRIDX_LC_BOOLEAN;
71263 break;
71264 }
71265 case DUK_TAG_POINTER: {
71266 /* implementation specific */
71267 stridx = DUK_STRIDX_LC_POINTER;
71268 break;
71269 }
71270 case DUK_TAG_STRING: {
71271 stridx = DUK_STRIDX_LC_STRING;
71272 break;
71273 }
71274 case DUK_TAG_OBJECT: {
71275 duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv_x);
71276 DUK_ASSERT(obj != NULL);
71277 if (DUK_HOBJECT_IS_CALLABLE(obj)) {
71278 stridx = DUK_STRIDX_LC_FUNCTION;
71279 } else {
71280 stridx = DUK_STRIDX_LC_OBJECT;
71281 }
71282 break;
71283 }
71284 case DUK_TAG_BUFFER: {
71285 /* implementation specific */
71286 stridx = DUK_STRIDX_LC_BUFFER;
71287 break;
71288 }
71289 case DUK_TAG_LIGHTFUNC: {
71290 stridx = DUK_STRIDX_LC_FUNCTION;
71291 break;
71292 }
71293#if defined(DUK_USE_FASTINT)
71294 case DUK_TAG_FASTINT:
71295#endif
71296 default: {
71297 /* number */
11fdf7f2 71298 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_x));
7c673cae
FG
71299 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_x));
71300 stridx = DUK_STRIDX_LC_NUMBER;
71301 break;
71302 }
71303 }
71304
71305 DUK_ASSERT(stridx >= 0 && stridx < DUK_HEAP_NUM_STRINGS);
71306 return DUK_HTHREAD_GET_STRING(thr, stridx);
71307}
71308
71309/*
71310 * Array index and length
71311 *
71312 * Array index: E5 Section 15.4
71313 * Array length: E5 Section 15.4.5.1 steps 3.c - 3.d (array length write)
71314 *
71315 * The DUK_HSTRING_GET_ARRIDX_SLOW() and DUK_HSTRING_GET_ARRIDX_FAST() macros
71316 * call duk_js_to_arrayindex_string_helper().
71317 */
71318
71319DUK_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) {
11fdf7f2 71320 duk_uarridx_t res;
7c673cae
FG
71321
71322 if (blen == 0 || blen > 10) {
71323 goto parse_fail;
71324 }
11fdf7f2 71325 if (str[0] == DUK_ASC_0 && blen > 1) {
7c673cae
FG
71326 goto parse_fail;
71327 }
71328
71329 /* Accept 32-bit decimal integers, no leading zeroes, signs, etc.
71330 * Leading zeroes are not accepted (zero index "0" is an exception
71331 * handled above).
71332 */
71333
71334 res = 0;
71335 while (blen-- > 0) {
71336 duk_uint8_t c = *str++;
11fdf7f2
TL
71337 if (c >= DUK_ASC_0 && c <= DUK_ASC_9) {
71338 /* Careful overflow handling. When multiplying by 10:
71339 * - 0x19999998 x 10 = 0xfffffff0: no overflow, and adding
71340 * 0...9 is safe.
71341 * - 0x19999999 x 10 = 0xfffffffa: no overflow, adding
71342 * 0...5 is safe, 6...9 overflows.
71343 * - 0x1999999a x 10 = 0x100000004: always overflow.
71344 */
71345 if (DUK_UNLIKELY(res >= 0x19999999UL)) {
71346 if (res >= 0x1999999aUL) {
71347 /* Always overflow. */
71348 goto parse_fail;
71349 }
71350 DUK_ASSERT(res == 0x19999999UL);
71351 c -= DUK_ASC_0;
71352 if (c >= 6) {
71353 goto parse_fail;
71354 }
71355 res = 0xfffffffaUL + c;
71356 DUK_ASSERT(res >= 0xfffffffaUL);
71357 DUK_ASSERT_DISABLE(res <= 0xffffffffUL); /* range */
71358 } else {
71359 res = res * 10U + (duk_uint32_t) (c - DUK_ASC_0);
7c673cae 71360 }
7c673cae
FG
71361 } else {
71362 goto parse_fail;
71363 }
71364 }
71365
71366 *out_idx = res;
71367 return 1;
71368
71369 parse_fail:
71370 *out_idx = DUK_HSTRING_NO_ARRAY_INDEX;
71371 return 0;
71372}
71373
71374/* Called by duk_hstring.h macros */
71375DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_string_helper(duk_hstring *h) {
71376 duk_uarridx_t res;
71377 duk_small_int_t rc;
71378
71379 if (!DUK_HSTRING_HAS_ARRIDX(h)) {
71380 return DUK_HSTRING_NO_ARRAY_INDEX;
71381 }
71382
71383 rc = duk_js_to_arrayindex_raw_string(DUK_HSTRING_GET_DATA(h),
71384 DUK_HSTRING_GET_BYTELEN(h),
71385 &res);
71386 DUK_UNREF(rc);
71387 DUK_ASSERT(rc != 0);
71388 return res;
71389}
7c673cae
FG
71390/*
71391 * Identifier access and function closure handling.
71392 *
71393 * Provides the primitives for slow path identifier accesses: GETVAR,
71394 * PUTVAR, DELVAR, etc. The fast path, direct register accesses, should
71395 * be used for most identifier accesses. Consequently, these slow path
71396 * primitives should be optimized for maximum compactness.
71397 *
71398 * Ecmascript environment records (declarative and object) are represented
71399 * as internal objects with control keys. Environment records have a
71400 * parent record ("outer environment reference") which is represented by
71401 * the implicit prototype for technical reasons (in other words, it is a
71402 * convenient field). The prototype chain is not followed in the ordinary
71403 * sense for variable lookups.
71404 *
71405 * See identifier-handling.rst for more details on the identifier algorithms
71406 * and the internal representation. See function-objects.rst for details on
71407 * what function templates and instances are expected to look like.
71408 *
71409 * Care must be taken to avoid duk_tval pointer invalidation caused by
71410 * e.g. value stack or object resizing.
71411 *
71412 * TODO: properties for function instances could be initialized much more
71413 * efficiently by creating a property allocation for a certain size and
71414 * filling in keys and values directly (and INCREFing both with "bulk incref"
71415 * primitives.
71416 *
71417 * XXX: duk_hobject_getprop() and duk_hobject_putprop() calls are a bit
71418 * awkward (especially because they follow the prototype chain); rework
71419 * if "raw" own property helpers are added.
71420 */
71421
71422/* include removed: duk_internal.h */
71423
71424/*
71425 * Local result type for duk__get_identifier_reference() lookup.
71426 */
71427
71428typedef struct {
71429 duk_hobject *holder; /* for object-bound identifiers */
71430 duk_tval *value; /* for register-bound and declarative env identifiers */
71431 duk_int_t attrs; /* property attributes for identifier (relevant if value != NULL) */
71432 duk_tval *this_binding;
71433 duk_hobject *env;
71434} duk__id_lookup_result;
71435
71436/*
71437 * Create a new function object based on a "template function" which contains
71438 * compiled bytecode, constants, etc, but lacks a lexical environment.
71439 *
71440 * Ecmascript requires that each created closure is a separate object, with
71441 * its own set of editable properties. However, structured property values
71442 * (such as the formal arguments list and the variable map) are shared.
71443 * Also the bytecode, constants, and inner functions are shared.
71444 *
71445 * See E5 Section 13.2 for detailed requirements on the function objects;
71446 * there are no similar requirements for function "templates" which are an
71447 * implementation dependent internal feature. Also see function-objects.rst
71448 * for a discussion on the function instance properties provided by this
71449 * implementation.
71450 *
71451 * Notes:
71452 *
71453 * * Order of internal properties should match frequency of use, since the
71454 * properties will be linearly scanned on lookup (functions usually don't
71455 * have enough properties to warrant a hash part).
71456 *
71457 * * The created closure is independent of its template; they do share the
71458 * same 'data' buffer object, but the template object itself can be freed
71459 * even if the closure object remains reachable.
71460 */
71461
71462DUK_LOCAL void duk__inc_data_inner_refcounts(duk_hthread *thr, duk_hcompiledfunction *f) {
71463 duk_tval *tv, *tv_end;
71464 duk_hobject **funcs, **funcs_end;
71465
11fdf7f2
TL
71466 /* If function creation fails due to out-of-memory, the data buffer
71467 * pointer may be NULL in some cases. That's actually possible for
71468 * GC code, but shouldn't be possible here because the incomplete
71469 * function will be unwound from the value stack and never instantiated.
71470 */
71471 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, f) != NULL);
7c673cae
FG
71472 DUK_UNREF(thr);
71473
71474 tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, f);
71475 tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, f);
71476 while (tv < tv_end) {
71477 DUK_TVAL_INCREF(thr, tv);
71478 tv++;
71479 }
71480
71481 funcs = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, f);
71482 funcs_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, f);
71483 while (funcs < funcs_end) {
71484 DUK_HEAPHDR_INCREF(thr, (duk_heaphdr *) *funcs);
71485 funcs++;
71486 }
71487}
71488
71489/* Push a new closure on the stack.
71490 *
71491 * Note: if fun_temp has NEWENV, i.e. a new lexical and variable declaration
71492 * is created when the function is called, only outer_lex_env matters
71493 * (outer_var_env is ignored and may or may not be same as outer_lex_env).
71494 */
71495
71496DUK_LOCAL const duk_uint16_t duk__closure_copy_proplist[] = {
71497 /* order: most frequent to least frequent */
71498 DUK_STRIDX_INT_VARMAP,
71499 DUK_STRIDX_INT_FORMALS,
71500 DUK_STRIDX_NAME,
71501 DUK_STRIDX_INT_PC2LINE,
71502 DUK_STRIDX_FILE_NAME,
71503 DUK_STRIDX_INT_SOURCE
71504};
71505
71506DUK_INTERNAL
71507void duk_js_push_closure(duk_hthread *thr,
71508 duk_hcompiledfunction *fun_temp,
71509 duk_hobject *outer_var_env,
11fdf7f2
TL
71510 duk_hobject *outer_lex_env,
71511 duk_bool_t add_auto_proto) {
7c673cae
FG
71512 duk_context *ctx = (duk_context *) thr;
71513 duk_hcompiledfunction *fun_clos;
71514 duk_small_uint_t i;
71515 duk_uint_t len_value;
71516
71517 DUK_ASSERT(fun_temp != NULL);
71518 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, fun_temp) != NULL);
71519 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_FUNCS(thr->heap, fun_temp) != NULL);
71520 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_BYTECODE(thr->heap, fun_temp) != NULL);
71521 DUK_ASSERT(outer_var_env != NULL);
71522 DUK_ASSERT(outer_lex_env != NULL);
11fdf7f2 71523 DUK_UNREF(len_value);
7c673cae
FG
71524
71525 duk_push_compiledfunction(ctx);
71526 duk_push_hobject(ctx, &fun_temp->obj); /* -> [ ... closure template ] */
71527
71528 fun_clos = (duk_hcompiledfunction *) duk_get_hcompiledfunction(ctx, -2);
71529 DUK_ASSERT(fun_clos != NULL);
71530 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) fun_clos));
71531 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, fun_clos) == NULL);
71532 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_FUNCS(thr->heap, fun_clos) == NULL);
71533 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_BYTECODE(thr->heap, fun_clos) == NULL);
71534
71535 DUK_HCOMPILEDFUNCTION_SET_DATA(thr->heap, fun_clos, DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, fun_temp));
71536 DUK_HCOMPILEDFUNCTION_SET_FUNCS(thr->heap, fun_clos, DUK_HCOMPILEDFUNCTION_GET_FUNCS(thr->heap, fun_temp));
71537 DUK_HCOMPILEDFUNCTION_SET_BYTECODE(thr->heap, fun_clos, DUK_HCOMPILEDFUNCTION_GET_BYTECODE(thr->heap, fun_temp));
71538
71539 /* Note: all references inside 'data' need to get their refcounts
71540 * upped too. This is the case because refcounts are decreased
71541 * through every function referencing 'data' independently.
71542 */
71543
71544 DUK_HBUFFER_INCREF(thr, DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, fun_clos));
71545 duk__inc_data_inner_refcounts(thr, fun_temp);
71546
71547 fun_clos->nregs = fun_temp->nregs;
71548 fun_clos->nargs = fun_temp->nargs;
71549#if defined(DUK_USE_DEBUGGER_SUPPORT)
71550 fun_clos->start_line = fun_temp->start_line;
71551 fun_clos->end_line = fun_temp->end_line;
71552#endif
71553
71554 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, fun_clos) != NULL);
71555 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_FUNCS(thr->heap, fun_clos) != NULL);
71556 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_BYTECODE(thr->heap, fun_clos) != NULL);
71557
71558 /* XXX: could also copy from template, but there's no way to have any
71559 * other value here now (used code has no access to the template).
71560 */
71561 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, &fun_clos->obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
71562
71563 /*
71564 * Init/assert flags, copying them where appropriate. Some flags
71565 * (like NEWENV) are processed separately below.
71566 */
71567
71568 /* XXX: copy flags using a mask */
71569
71570 DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(&fun_clos->obj));
71571 DUK_HOBJECT_SET_CONSTRUCTABLE(&fun_clos->obj); /* Note: not set in template (has no "prototype") */
71572 DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE(&fun_clos->obj));
71573 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(&fun_clos->obj));
71574 DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(&fun_clos->obj));
71575 DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(&fun_clos->obj));
71576 DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(&fun_clos->obj));
71577 /* DUK_HOBJECT_FLAG_ARRAY_PART: don't care */
71578 if (DUK_HOBJECT_HAS_STRICT(&fun_temp->obj)) {
71579 DUK_HOBJECT_SET_STRICT(&fun_clos->obj);
71580 }
71581 if (DUK_HOBJECT_HAS_NOTAIL(&fun_temp->obj)) {
71582 DUK_HOBJECT_SET_NOTAIL(&fun_clos->obj);
71583 }
71584 /* DUK_HOBJECT_FLAG_NEWENV: handled below */
71585 if (DUK_HOBJECT_HAS_NAMEBINDING(&fun_temp->obj)) {
71586 /* Although NAMEBINDING is not directly needed for using
71587 * function instances, it's needed by bytecode dump/load
71588 * so copy it too.
71589 */
71590 DUK_HOBJECT_SET_NAMEBINDING(&fun_clos->obj);
71591 }
71592 if (DUK_HOBJECT_HAS_CREATEARGS(&fun_temp->obj)) {
71593 DUK_HOBJECT_SET_CREATEARGS(&fun_clos->obj);
71594 }
71595 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(&fun_clos->obj));
71596 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(&fun_clos->obj));
71597 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(&fun_clos->obj));
71598
71599 /*
71600 * Setup environment record properties based on the template and
71601 * its flags.
71602 *
71603 * If DUK_HOBJECT_HAS_NEWENV(fun_temp) is true, the environment
71604 * records represent identifiers "outside" the function; the
71605 * "inner" environment records are created on demand. Otherwise,
71606 * the environment records are those that will be directly used
71607 * (e.g. for declarations).
71608 *
71609 * _Lexenv is always set; _Varenv defaults to _Lexenv if missing,
71610 * so _Varenv is only set if _Lexenv != _Varenv.
71611 *
71612 * This is relatively complex, see doc/identifier-handling.rst.
71613 */
71614
71615 if (DUK_HOBJECT_HAS_NEWENV(&fun_temp->obj)) {
71616 DUK_HOBJECT_SET_NEWENV(&fun_clos->obj);
71617
71618 if (DUK_HOBJECT_HAS_NAMEBINDING(&fun_temp->obj)) {
71619 duk_hobject *proto;
71620
71621 /*
71622 * Named function expression, name needs to be bound
71623 * in an intermediate environment record. The "outer"
71624 * lexical/variable environment will thus be:
71625 *
71626 * a) { funcname: <func>, __prototype: outer_lex_env }
71627 * b) { funcname: <func>, __prototype: <globalenv> } (if outer_lex_env missing)
71628 */
71629
71630 DUK_ASSERT(duk_has_prop_stridx(ctx, -1, DUK_STRIDX_NAME)); /* required if NAMEBINDING set */
71631
71632 if (outer_lex_env) {
71633 proto = outer_lex_env;
71634 } else {
71635 proto = thr->builtins[DUK_BIDX_GLOBAL_ENV];
71636 }
71637
71638 /* -> [ ... closure template env ] */
71639 (void) duk_push_object_helper_proto(ctx,
71640 DUK_HOBJECT_FLAG_EXTENSIBLE |
71641 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
71642 proto);
71643
71644 /* It's important that duk_xdef_prop() is a 'raw define' so that any
71645 * properties in an ancestor are never an issue (they should never be
71646 * e.g. non-writable, but just in case).
71647 */
71648 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME); /* -> [ ... closure template env funcname ] */
71649 duk_dup(ctx, -4); /* -> [ ... closure template env funcname closure ] */
71650 duk_xdef_prop(ctx, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ ... closure template env ] */
71651 /* env[funcname] = closure */
71652
71653 /* [ ... closure template env ] */
71654
71655 duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_INT_LEXENV, DUK_PROPDESC_FLAGS_WC);
71656 /* since closure has NEWENV, never define DUK_STRIDX_INT_VARENV, as it
71657 * will be ignored anyway
71658 */
71659
71660 /* [ ... closure template ] */
71661 } else {
71662 /*
71663 * Other cases (function declaration, anonymous function expression,
71664 * strict direct eval code). The "outer" environment will be whatever
71665 * the caller gave us.
71666 */
71667
71668 duk_push_hobject(ctx, outer_lex_env); /* -> [ ... closure template env ] */
71669 duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_INT_LEXENV, DUK_PROPDESC_FLAGS_WC);
71670 /* since closure has NEWENV, never define DUK_STRIDX_INT_VARENV, as it
71671 * will be ignored anyway
71672 */
71673
71674 /* [ ... closure template ] */
71675 }
71676 } else {
71677 /*
71678 * Function gets no new environment when called. This is the
71679 * case for global code, indirect eval code, and non-strict
71680 * direct eval code. There is no direct correspondence to the
71681 * E5 specification, as global/eval code is not exposed as a
71682 * function.
71683 */
71684
71685 DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(&fun_temp->obj));
71686
71687 duk_push_hobject(ctx, outer_lex_env); /* -> [ ... closure template env ] */
71688 duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_INT_LEXENV, DUK_PROPDESC_FLAGS_WC);
71689
71690 if (outer_var_env != outer_lex_env) {
71691 duk_push_hobject(ctx, outer_var_env); /* -> [ ... closure template env ] */
71692 duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_INT_VARENV, DUK_PROPDESC_FLAGS_WC);
71693 }
71694 }
71695#ifdef DUK_USE_DDDPRINT
71696 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_INT_VARENV);
71697 duk_get_prop_stridx(ctx, -3, DUK_STRIDX_INT_LEXENV);
71698 DUK_DDD(DUK_DDDPRINT("closure varenv -> %!ipT, lexenv -> %!ipT",
71699 (duk_tval *) duk_get_tval(ctx, -2),
71700 (duk_tval *) duk_get_tval(ctx, -1)));
71701 duk_pop_2(ctx);
71702#endif
71703
71704 /*
71705 * Copy some internal properties directly
71706 *
71707 * The properties will be writable and configurable, but not enumerable.
71708 */
71709
71710 /* [ ... closure template ] */
71711
71712 DUK_DDD(DUK_DDDPRINT("copying properties: closure=%!iT, template=%!iT",
71713 (duk_tval *) duk_get_tval(ctx, -2),
71714 (duk_tval *) duk_get_tval(ctx, -1)));
71715
71716 for (i = 0; i < (duk_small_uint_t) (sizeof(duk__closure_copy_proplist) / sizeof(duk_uint16_t)); i++) {
71717 duk_small_int_t stridx = (duk_small_int_t) duk__closure_copy_proplist[i];
71718 if (duk_get_prop_stridx(ctx, -1, stridx)) {
71719 /* [ ... closure template val ] */
71720 DUK_DDD(DUK_DDDPRINT("copying property, stridx=%ld -> found", (long) stridx));
71721 duk_xdef_prop_stridx(ctx, -3, stridx, DUK_PROPDESC_FLAGS_WC);
71722 } else {
71723 DUK_DDD(DUK_DDDPRINT("copying property, stridx=%ld -> not found", (long) stridx));
71724 duk_pop(ctx);
71725 }
71726 }
71727
71728 /*
71729 * "length" maps to number of formals (E5 Section 13.2) for function
71730 * declarations/expressions (non-bound functions). Note that 'nargs'
71731 * is NOT necessarily equal to the number of arguments.
71732 */
71733
71734 /* [ ... closure template ] */
71735
71736 len_value = 0;
71737
71738 /* XXX: use helper for size optimization */
71739 if (duk_get_prop_stridx(ctx, -2, DUK_STRIDX_INT_FORMALS)) {
71740 /* [ ... closure template formals ] */
71741 DUK_ASSERT(duk_has_prop_stridx(ctx, -1, DUK_STRIDX_LENGTH));
71742 DUK_ASSERT(duk_get_length(ctx, -1) <= DUK_UINT_MAX); /* formal arg limits */
71743 len_value = (duk_uint_t) duk_get_length(ctx, -1);
71744 } else {
71745 /* XXX: what to do if _Formals is not empty but compiler has
71746 * optimized it away -- read length from an explicit property
71747 * then?
71748 */
71749 }
71750 duk_pop(ctx);
71751
71752 duk_push_uint(ctx, len_value); /* [ ... closure template len_value ] */
71753 duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
71754
71755 /*
71756 * "prototype" is, by default, a fresh object with the "constructor"
71757 * property.
71758 *
71759 * Note that this creates a circular reference for every function
71760 * instance (closure) which prevents refcount-based collection of
71761 * function instances.
71762 *
71763 * XXX: Try to avoid creating the default prototype object, because
71764 * many functions are not used as constructors and the default
71765 * prototype is unnecessary. Perhaps it could be created on-demand
71766 * when it is first accessed?
71767 */
71768
71769 /* [ ... closure template ] */
71770
11fdf7f2
TL
71771 if (add_auto_proto) {
71772 duk_push_object(ctx); /* -> [ ... closure template newobj ] */
71773 duk_dup(ctx, -3); /* -> [ ... closure template newobj closure ] */
71774 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* -> [ ... closure template newobj ] */
71775 duk_compact(ctx, -1); /* compact the prototype */
71776 duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W); /* -> [ ... closure template ] */
71777 }
7c673cae
FG
71778
71779 /*
71780 * "arguments" and "caller" must be mapped to throwers for strict
71781 * mode and bound functions (E5 Section 15.3.5).
71782 *
71783 * XXX: This is expensive to have for every strict function instance.
71784 * Try to implement as virtual properties or on-demand created properties.
71785 */
71786
71787 /* [ ... closure template ] */
71788
71789 if (DUK_HOBJECT_HAS_STRICT(&fun_clos->obj)) {
71790 duk_xdef_prop_stridx_thrower(ctx, -2, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
71791 duk_xdef_prop_stridx_thrower(ctx, -2, DUK_STRIDX_LC_ARGUMENTS, DUK_PROPDESC_FLAGS_NONE);
71792 } else {
71793#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
71794 DUK_DDD(DUK_DDDPRINT("function is non-strict and non-standard 'caller' property in use, add initial 'null' value"));
71795 duk_push_null(ctx);
71796 duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
71797#else
71798 DUK_DDD(DUK_DDDPRINT("function is non-strict and non-standard 'caller' property not used"));
71799#endif
71800 }
71801
71802 /*
71803 * "name" is a non-standard property found in at least V8, Rhino, smjs.
71804 * For Rhino and smjs it is non-writable, non-enumerable, and non-configurable;
71805 * for V8 it is writable, non-enumerable, non-configurable. It is also defined
71806 * for an anonymous function expression in which case the value is an empty string.
71807 * We could also leave name 'undefined' for anonymous functions but that would
71808 * differ from behavior of other engines, so use an empty string.
71809 *
71810 * XXX: make optional? costs something per function.
71811 */
71812
71813 /* [ ... closure template ] */
71814
71815 if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME)) {
71816 /* [ ... closure template name ] */
71817 DUK_ASSERT(duk_is_string(ctx, -1));
71818 } else {
71819 /* [ ... closure template undefined ] */
71820 duk_pop(ctx);
71821 duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
71822 }
71823 duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE); /* -> [ ... closure template ] */
71824
71825 /*
71826 * Compact the closure, in most cases no properties will be added later.
71827 * Also, without this the closures end up having unused property slots
71828 * (e.g. in Duktape 0.9.0, 8 slots would be allocated and only 7 used).
71829 * A better future solution would be to allocate the closure directly
71830 * to correct size (and setup the properties directly without going
71831 * through the API).
71832 */
71833
71834 duk_compact(ctx, -2);
71835
71836 /*
71837 * Some assertions (E5 Section 13.2).
71838 */
71839
71840 DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(&fun_clos->obj) == DUK_HOBJECT_CLASS_FUNCTION);
71841 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, &fun_clos->obj) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
71842 DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(&fun_clos->obj));
71843 DUK_ASSERT(duk_has_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH) != 0);
11fdf7f2 71844 DUK_ASSERT(add_auto_proto == 0 || duk_has_prop_stridx(ctx, -2, DUK_STRIDX_PROTOTYPE) != 0);
7c673cae
FG
71845 DUK_ASSERT(duk_has_prop_stridx(ctx, -2, DUK_STRIDX_NAME) != 0); /* non-standard */
71846 DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(&fun_clos->obj) ||
71847 duk_has_prop_stridx(ctx, -2, DUK_STRIDX_CALLER) != 0);
71848 DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(&fun_clos->obj) ||
71849 duk_has_prop_stridx(ctx, -2, DUK_STRIDX_LC_ARGUMENTS) != 0);
71850
71851 /*
71852 * Finish
71853 */
71854
71855 /* [ ... closure template ] */
71856
71857 DUK_DDD(DUK_DDDPRINT("created function instance: template=%!iT -> closure=%!iT",
71858 (duk_tval *) duk_get_tval(ctx, -1),
71859 (duk_tval *) duk_get_tval(ctx, -2)));
71860
71861 duk_pop(ctx);
71862
71863 /* [ ... closure ] */
71864}
71865
71866/*
71867 * Delayed activation environment record initialization (for functions
71868 * with NEWENV).
71869 *
71870 * The non-delayed initialization is handled by duk_handle_call().
71871 */
71872
71873/* shared helper */
71874DUK_INTERNAL
71875duk_hobject *duk_create_activation_environment_record(duk_hthread *thr,
71876 duk_hobject *func,
71877 duk_size_t idx_bottom) {
71878 duk_context *ctx = (duk_context *) thr;
71879 duk_hobject *env;
71880 duk_hobject *parent;
71881 duk_tval *tv;
71882
71883 DUK_ASSERT(thr != NULL);
71884 DUK_ASSERT(func != NULL);
71885
71886 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_LEXENV(thr));
71887 if (tv) {
71888 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
71889 DUK_ASSERT(DUK_HOBJECT_IS_ENV(DUK_TVAL_GET_OBJECT(tv)));
71890 parent = DUK_TVAL_GET_OBJECT(tv);
71891 } else {
71892 parent = thr->builtins[DUK_BIDX_GLOBAL_ENV];
71893 }
71894
71895 (void) duk_push_object_helper(ctx,
71896 DUK_HOBJECT_FLAG_EXTENSIBLE |
71897 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
71898 -1); /* no prototype, updated below */
71899 env = duk_require_hobject(ctx, -1);
71900 DUK_ASSERT(env != NULL);
71901 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, env, parent); /* parent env is the prototype */
71902
71903 /* open scope information, for compiled functions only */
71904
71905 if (DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
71906 duk_push_hthread(ctx, thr);
71907 duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_INT_THREAD);
71908 duk_push_hobject(ctx, func);
71909 duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_INT_CALLEE);
71910 duk_push_size_t(ctx, idx_bottom);
71911 duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_INT_REGBASE);
71912 }
71913
71914 return env;
71915}
71916
71917DUK_INTERNAL
71918void duk_js_init_activation_environment_records_delayed(duk_hthread *thr,
71919 duk_activation *act) {
71920 duk_context *ctx = (duk_context *) thr;
71921 duk_hobject *func;
71922 duk_hobject *env;
11fdf7f2 71923 duk_size_t act_off;
7c673cae 71924
11fdf7f2
TL
71925 DUK_ASSERT(act != NULL);
71926 act_off = (duk_size_t) ((duk_uint8_t *) act - (duk_uint8_t *) thr->callstack);
7c673cae
FG
71927 func = DUK_ACT_GET_FUNC(act);
71928 DUK_ASSERT(func != NULL);
71929 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func)); /* bound functions are never in act 'func' */
71930
71931 /*
71932 * Delayed initialization only occurs for 'NEWENV' functions.
71933 */
71934
71935 DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
71936 DUK_ASSERT(act->lex_env == NULL);
71937 DUK_ASSERT(act->var_env == NULL);
71938
71939 env = duk_create_activation_environment_record(thr, func, act->idx_bottom);
71940 DUK_ASSERT(env != NULL);
11fdf7f2 71941 act = (duk_activation *) ((duk_uint8_t *) thr->callstack + act_off);
7c673cae
FG
71942
71943 DUK_DDD(DUK_DDDPRINT("created delayed fresh env: %!ipO", (duk_heaphdr *) env));
71944#ifdef DUK_USE_DDDPRINT
71945 {
71946 duk_hobject *p = env;
71947 while (p) {
71948 DUK_DDD(DUK_DDDPRINT(" -> %!ipO", (duk_heaphdr *) p));
71949 p = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, p);
71950 }
71951 }
71952#endif
71953
71954 act->lex_env = env;
71955 act->var_env = env;
71956 DUK_HOBJECT_INCREF(thr, env); /* XXX: incref by count (here 2 times) */
71957 DUK_HOBJECT_INCREF(thr, env);
71958
71959 duk_pop(ctx);
71960}
71961
71962/*
71963 * Closing environment records.
71964 *
71965 * The environment record MUST be closed with the thread where its activation
71966 * is. In other words (if 'env' is open):
71967 *
71968 * - 'thr' must match _env.thread
71969 * - 'func' must match _env.callee
71970 * - 'regbase' must match _env.regbase
71971 *
71972 * These are not looked up from the env to minimize code size.
71973 *
71974 * XXX: should access the own properties directly instead of using the API
71975 */
71976
71977DUK_INTERNAL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env, duk_hobject *func, duk_size_t regbase) {
71978 duk_context *ctx = (duk_context *) thr;
71979 duk_uint_fast32_t i;
71980
71981 DUK_ASSERT(thr != NULL);
71982 DUK_ASSERT(env != NULL);
71983 /* func is NULL for lightfuncs */
71984
71985 if (!DUK_HOBJECT_IS_DECENV(env) || DUK_HOBJECT_HAS_ENVRECCLOSED(env)) {
71986 DUK_DDD(DUK_DDDPRINT("environment record not a declarative record, "
71987 "or already closed: %!iO",
71988 (duk_heaphdr *) env));
71989 return;
71990 }
71991
71992 DUK_DDD(DUK_DDDPRINT("closing environment record: %!iO, func: %!iO, regbase: %ld",
71993 (duk_heaphdr *) env, (duk_heaphdr *) func, (long) regbase));
71994
71995 duk_push_hobject(ctx, env);
71996
71997 /* assertions: env must be closed in the same thread as where it runs */
71998#ifdef DUK_USE_ASSERTIONS
71999 {
72000 /* [... env] */
72001
72002 if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_CALLEE)) {
72003 DUK_ASSERT(duk_is_object(ctx, -1));
72004 DUK_ASSERT(duk_get_hobject(ctx, -1) == (duk_hobject *) func);
72005 }
72006 duk_pop(ctx);
72007
72008 if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_THREAD)) {
72009 DUK_ASSERT(duk_is_object(ctx, -1));
72010 DUK_ASSERT(duk_get_hobject(ctx, -1) == (duk_hobject *) thr);
72011 }
72012 duk_pop(ctx);
72013
72014 if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_REGBASE)) {
72015 DUK_ASSERT(duk_is_number(ctx, -1));
72016 DUK_ASSERT(duk_get_number(ctx, -1) == (double) regbase);
72017 }
72018 duk_pop(ctx);
72019
72020 /* [... env] */
72021 }
72022#endif
72023
72024 if (func != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
72025 duk_hobject *varmap;
72026 duk_hstring *key;
72027 duk_tval *tv;
72028 duk_uint_t regnum;
72029
72030 /* XXX: additional conditions when to close variables? we don't want to do it
72031 * unless the environment may have "escaped" (referenced in a function closure).
72032 * With delayed environments, the existence is probably good enough of a check.
72033 */
72034
72035 /* XXX: any way to detect faster whether something needs to be closed?
72036 * We now look up _Callee and then skip the rest.
72037 */
72038
72039 /* Note: we rely on the _Varmap having a bunch of nice properties, like:
72040 * - being compacted and unmodified during this process
72041 * - not containing an array part
72042 * - having correct value types
72043 */
72044
72045 /* [... env] */
72046
72047 if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_CALLEE)) {
72048 DUK_DDD(DUK_DDDPRINT("env has no callee property, nothing to close; re-delete the control properties just in case"));
72049 duk_pop(ctx);
72050 goto skip_varmap;
72051 }
72052
72053 /* [... env callee] */
72054
72055 if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VARMAP)) {
72056 DUK_DDD(DUK_DDDPRINT("callee has no varmap property, nothing to close; delete the control properties"));
72057 duk_pop_2(ctx);
72058 goto skip_varmap;
72059 }
72060 varmap = duk_require_hobject(ctx, -1);
72061 DUK_ASSERT(varmap != NULL);
72062
72063 DUK_DDD(DUK_DDDPRINT("varmap: %!O", (duk_heaphdr *) varmap));
72064
72065 /* [... env callee varmap] */
72066
72067 DUK_DDD(DUK_DDDPRINT("copying bound register values, %ld bound regs", (long) DUK_HOBJECT_GET_ENEXT(varmap)));
72068
72069 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(varmap); i++) {
72070 key = DUK_HOBJECT_E_GET_KEY(thr->heap, varmap, i);
72071 DUK_ASSERT(key != NULL); /* assume keys are compacted */
72072
72073 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, varmap, i)); /* assume plain values */
72074
72075 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, varmap, i);
72076 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); /* assume value is a number */
72077 regnum = (duk_uint_t) DUK_TVAL_GET_NUMBER(tv);
72078 DUK_ASSERT_DISABLE(regnum >= 0); /* unsigned */
72079 DUK_ASSERT(regnum < ((duk_hcompiledfunction *) func)->nregs); /* regnum is sane */
72080 DUK_ASSERT(thr->valstack + regbase + regnum >= thr->valstack);
72081 DUK_ASSERT(thr->valstack + regbase + regnum < thr->valstack_top);
72082
72083 /* XXX: slightly awkward */
72084 duk_push_hstring(ctx, key);
72085 duk_push_tval(ctx, thr->valstack + regbase + regnum);
72086 DUK_DDD(DUK_DDDPRINT("closing identifier '%s' -> reg %ld, value %!T",
72087 (const char *) duk_require_string(ctx, -2),
72088 (long) regnum,
72089 (duk_tval *) duk_get_tval(ctx, -1)));
72090
72091 /* [... env callee varmap key val] */
72092
72093 /* if property already exists, overwrites silently */
72094 duk_xdef_prop(ctx, -5, DUK_PROPDESC_FLAGS_WE); /* writable but not deletable */
72095 }
72096
72097 duk_pop_2(ctx);
72098
72099 /* [... env] */
72100 }
72101
72102 skip_varmap:
72103
72104 /* [... env] */
72105
72106 duk_del_prop_stridx(ctx, -1, DUK_STRIDX_INT_CALLEE);
72107 duk_del_prop_stridx(ctx, -1, DUK_STRIDX_INT_THREAD);
72108 duk_del_prop_stridx(ctx, -1, DUK_STRIDX_INT_REGBASE);
72109
72110 duk_pop(ctx);
72111
72112 DUK_HOBJECT_SET_ENVRECCLOSED(env);
72113
72114 DUK_DDD(DUK_DDDPRINT("environment record after being closed: %!O",
72115 (duk_heaphdr *) env));
72116}
72117
72118/*
72119 * GETIDREF: a GetIdentifierReference-like helper.
72120 *
72121 * Provides a parent traversing lookup and a single level lookup
72122 * (for HasBinding).
72123 *
72124 * Instead of returning the value, returns a bunch of values allowing
72125 * the caller to read, write, or delete the binding. Value pointers
72126 * are duk_tval pointers which can be mutated directly as long as
72127 * refcounts are properly updated. Note that any operation which may
72128 * reallocate valstacks or compact objects may invalidate the returned
72129 * duk_tval (but not object) pointers, so caller must be very careful.
72130 *
72131 * If starting environment record 'env' is given, 'act' is ignored.
72132 * However, if 'env' is NULL, the caller may identify, in 'act', an
72133 * activation which hasn't had its declarative environment initialized
72134 * yet. The activation registers are then looked up, and its parent
72135 * traversed normally.
72136 *
72137 * The 'out' structure values are only valid if the function returns
72138 * success (non-zero).
72139 */
72140
72141/* lookup name from an open declarative record's registers */
72142DUK_LOCAL
72143duk_bool_t duk__getid_open_decl_env_regs(duk_hthread *thr,
72144 duk_hstring *name,
72145 duk_hobject *env,
72146 duk__id_lookup_result *out) {
72147 duk_hthread *env_thr;
72148 duk_hobject *env_func;
72149 duk_size_t env_regbase;
72150 duk_hobject *varmap;
72151 duk_tval *tv;
72152 duk_size_t reg_rel;
72153 duk_size_t idx;
72154
72155 DUK_ASSERT(thr != NULL);
72156 DUK_ASSERT(name != NULL);
72157 DUK_ASSERT(env != NULL);
72158 DUK_ASSERT(out != NULL);
72159
72160 DUK_ASSERT(DUK_HOBJECT_IS_DECENV(env));
72161
72162 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_CALLEE(thr));
72163 if (!tv) {
72164 /* env is closed, should be missing _Callee, _Thread, _Regbase */
72165 DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL);
72166 DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL);
72167 DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL);
72168 return 0;
72169 }
72170
72171 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
72172 DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL);
72173 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_TVAL_GET_OBJECT(tv)));
72174 env_func = DUK_TVAL_GET_OBJECT(tv);
72175 DUK_ASSERT(env_func != NULL);
72176
72177 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env_func, DUK_HTHREAD_STRING_INT_VARMAP(thr));
72178 if (!tv) {
72179 return 0;
72180 }
72181 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
72182 varmap = DUK_TVAL_GET_OBJECT(tv);
72183 DUK_ASSERT(varmap != NULL);
72184
72185 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, varmap, name);
72186 if (!tv) {
72187 return 0;
72188 }
72189 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
72190 reg_rel = (duk_size_t) DUK_TVAL_GET_NUMBER(tv);
72191 DUK_ASSERT_DISABLE(reg_rel >= 0); /* unsigned */
72192 DUK_ASSERT(reg_rel < ((duk_hcompiledfunction *) env_func)->nregs);
72193
72194 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_THREAD(thr));
72195 DUK_ASSERT(tv != NULL);
72196 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
72197 DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL);
72198 DUK_ASSERT(DUK_HOBJECT_IS_THREAD(DUK_TVAL_GET_OBJECT(tv)));
72199 env_thr = (duk_hthread *) DUK_TVAL_GET_OBJECT(tv);
72200 DUK_ASSERT(env_thr != NULL);
72201
72202 /* Note: env_thr != thr is quite possible and normal, so careful
72203 * with what thread is used for valstack lookup.
72204 */
72205
72206 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_REGBASE(thr));
72207 DUK_ASSERT(tv != NULL);
72208 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
72209 env_regbase = (duk_size_t) DUK_TVAL_GET_NUMBER(tv);
72210
72211 idx = env_regbase + reg_rel;
72212 tv = env_thr->valstack + idx;
72213 DUK_ASSERT(tv >= env_thr->valstack && tv < env_thr->valstack_end); /* XXX: more accurate? */
72214
72215 out->value = tv;
72216 out->attrs = DUK_PROPDESC_FLAGS_W; /* registers are mutable, non-deletable */
72217 out->this_binding = NULL; /* implicit this value always undefined for
72218 * declarative environment records.
72219 */
72220 out->env = env;
72221 out->holder = NULL;
72222
72223 return 1;
72224}
72225
72226/* lookup name from current activation record's functions' registers */
72227DUK_LOCAL
72228duk_bool_t duk__getid_activation_regs(duk_hthread *thr,
72229 duk_hstring *name,
72230 duk_activation *act,
72231 duk__id_lookup_result *out) {
72232 duk_tval *tv;
72233 duk_hobject *func;
72234 duk_hobject *varmap;
72235 duk_size_t reg_rel;
72236 duk_size_t idx;
72237
72238 DUK_ASSERT(thr != NULL);
72239 DUK_ASSERT(name != NULL);
72240 DUK_ASSERT(act != NULL);
72241 DUK_ASSERT(out != NULL);
72242
72243 func = DUK_ACT_GET_FUNC(act);
72244 DUK_ASSERT(func != NULL);
72245 DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
72246
72247 if (!DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
72248 return 0;
72249 }
72250
72251 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_VARMAP(thr));
72252 if (!tv) {
72253 return 0;
72254 }
72255 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
72256 varmap = DUK_TVAL_GET_OBJECT(tv);
72257 DUK_ASSERT(varmap != NULL);
72258
72259 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, varmap, name);
72260 if (!tv) {
72261 return 0;
72262 }
72263 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
72264 reg_rel = (duk_size_t) DUK_TVAL_GET_NUMBER(tv);
72265 DUK_ASSERT_DISABLE(reg_rel >= 0);
72266 DUK_ASSERT(reg_rel < ((duk_hcompiledfunction *) func)->nregs);
72267
72268 idx = act->idx_bottom + reg_rel;
72269 DUK_ASSERT(idx >= act->idx_bottom);
72270 tv = thr->valstack + idx;
72271
72272 out->value = tv;
72273 out->attrs = DUK_PROPDESC_FLAGS_W; /* registers are mutable, non-deletable */
72274 out->this_binding = NULL; /* implicit this value always undefined for
72275 * declarative environment records.
72276 */
72277 out->env = NULL;
72278 out->holder = NULL;
72279
72280 return 1;
72281}
72282
72283DUK_LOCAL
72284duk_bool_t duk__get_identifier_reference(duk_hthread *thr,
72285 duk_hobject *env,
72286 duk_hstring *name,
72287 duk_activation *act,
72288 duk_bool_t parents,
72289 duk__id_lookup_result *out) {
72290 duk_tval *tv;
72291 duk_tval *tv_target;
72292 duk_tval tv_name;
72293 duk_uint_t sanity;
72294
72295 DUK_ASSERT(thr != NULL);
72296 DUK_ASSERT(env != NULL || act != NULL);
72297 DUK_ASSERT(name != NULL);
72298 DUK_ASSERT(out != NULL);
72299
72300 DUK_ASSERT(!env || DUK_HOBJECT_IS_ENV(env));
72301 DUK_ASSERT(!env || !DUK_HOBJECT_HAS_ARRAY_PART(env));
72302
72303 /*
72304 * Conceptually, we look for the identifier binding by starting from
72305 * 'env' and following to chain of environment records (represented
72306 * by the prototype chain).
72307 *
72308 * If 'env' is NULL, the current activation does not yet have an
72309 * allocated declarative environment record; this should be treated
72310 * exactly as if the environment record existed but had no bindings
72311 * other than register bindings.
72312 *
72313 * Note: we assume that with the DUK_HOBJECT_FLAG_NEWENV cleared
72314 * the environment will always be initialized immediately; hence
72315 * a NULL 'env' should only happen with the flag set. This is the
72316 * case for: (1) function calls, and (2) strict, direct eval calls.
72317 */
72318
72319 if (env == NULL && act != NULL) {
72320 duk_hobject *func;
72321
72322 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference: env is NULL, activation is non-NULL -> "
72323 "delayed env case, look up activation regs first"));
72324
72325 /*
72326 * Try registers
72327 */
72328
72329 if (duk__getid_activation_regs(thr, name, act, out)) {
72330 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
72331 "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O "
72332 "(found from register bindings when env=NULL)",
72333 (duk_heaphdr *) name, (duk_tval *) out->value,
72334 (long) out->attrs, (duk_tval *) out->this_binding,
72335 (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
72336 return 1;
72337 }
72338
72339 DUK_DDD(DUK_DDDPRINT("not found in current activation regs"));
72340
72341 /*
72342 * Not found in registers, proceed to the parent record.
72343 * Here we need to determine what the parent would be,
72344 * if 'env' was not NULL (i.e. same logic as when initializing
72345 * the record).
72346 *
72347 * Note that environment initialization is only deferred when
72348 * DUK_HOBJECT_HAS_NEWENV is set, and this only happens for:
72349 * - Function code
72350 * - Strict eval code
72351 *
72352 * We only need to check _Lexenv here; _Varenv exists only if it
72353 * differs from _Lexenv (and thus _Lexenv will also be present).
72354 */
72355
72356 if (!parents) {
72357 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference failed, no parent traversal "
72358 "(not found from register bindings when env=NULL)"));
72359 goto fail_not_found;
72360 }
72361
72362 func = DUK_ACT_GET_FUNC(act);
72363 DUK_ASSERT(func != NULL);
72364 DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
72365
72366 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_LEXENV(thr));
72367 if (tv) {
72368 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
72369 env = DUK_TVAL_GET_OBJECT(tv);
72370 } else {
72371 DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_VARENV(thr)) == NULL);
72372 env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
72373 }
72374
72375 DUK_DDD(DUK_DDDPRINT("continue lookup from env: %!iO",
72376 (duk_heaphdr *) env));
72377 }
72378
72379 /*
72380 * Prototype walking starting from 'env'.
72381 *
72382 * ('act' is not needed anywhere here.)
72383 */
72384
72385 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
72386 while (env != NULL) {
72387 duk_small_int_t cl;
72388 duk_int_t attrs;
72389
72390 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference, name=%!O, considering env=%p -> %!iO",
72391 (duk_heaphdr *) name,
72392 (void *) env,
72393 (duk_heaphdr *) env));
72394
72395 DUK_ASSERT(env != NULL);
72396 DUK_ASSERT(DUK_HOBJECT_IS_ENV(env));
72397 DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(env));
72398
72399 cl = DUK_HOBJECT_GET_CLASS_NUMBER(env);
72400 DUK_ASSERT(cl == DUK_HOBJECT_CLASS_OBJENV || cl == DUK_HOBJECT_CLASS_DECENV);
72401 if (cl == DUK_HOBJECT_CLASS_DECENV) {
72402 /*
72403 * Declarative environment record.
72404 *
72405 * Identifiers can never be stored in ancestors and are
72406 * always plain values, so we can use an internal helper
72407 * and access the value directly with an duk_tval ptr.
72408 *
72409 * A closed environment is only indicated by it missing
72410 * the "book-keeping" properties required for accessing
72411 * register-bound variables.
72412 */
72413
72414 if (DUK_HOBJECT_HAS_ENVRECCLOSED(env)) {
72415 /* already closed */
72416 goto skip_regs;
72417 }
72418
72419 if (duk__getid_open_decl_env_regs(thr, name, env, out)) {
72420 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
72421 "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O "
72422 "(declarative environment record, scope open, found in regs)",
72423 (duk_heaphdr *) name, (duk_tval *) out->value,
72424 (long) out->attrs, (duk_tval *) out->this_binding,
72425 (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
72426 return 1;
72427 }
72428 skip_regs:
72429
72430 tv = duk_hobject_find_existing_entry_tval_ptr_and_attrs(thr->heap, env, name, &attrs);
72431 if (tv) {
72432 out->value = tv;
72433 out->attrs = attrs;
72434 out->this_binding = NULL; /* implicit this value always undefined for
72435 * declarative environment records.
72436 */
72437 out->env = env;
72438 out->holder = env;
72439
72440 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
72441 "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O "
72442 "(declarative environment record, found in properties)",
72443 (duk_heaphdr *) name, (duk_tval *) out->value,
72444 (long) out->attrs, (duk_tval *) out->this_binding,
72445 (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
72446 return 1;
72447 }
72448 } else {
72449 /*
72450 * Object environment record.
72451 *
72452 * Binding (target) object is an external, uncontrolled object.
72453 * Identifier may be bound in an ancestor property, and may be
72454 * an accessor. Target can also be a Proxy which we must support
72455 * here.
72456 */
72457
72458 /* XXX: we could save space by using _Target OR _This. If _Target, assume
72459 * this binding is undefined. If _This, assumes this binding is _This, and
72460 * target is also _This. One property would then be enough.
72461 */
72462
72463 duk_hobject *target;
72464 duk_bool_t found;
72465
72466 DUK_ASSERT(cl == DUK_HOBJECT_CLASS_OBJENV);
72467
72468 tv_target = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_TARGET(thr));
72469 DUK_ASSERT(tv_target != NULL);
72470 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_target));
72471 target = DUK_TVAL_GET_OBJECT(tv_target);
72472 DUK_ASSERT(target != NULL);
72473
72474 /* Target may be a Proxy or property may be an accessor, so we must
72475 * use an actual, Proxy-aware hasprop check here.
72476 *
72477 * out->holder is NOT set to the actual duk_hobject where the
72478 * property is found, but rather the object binding target object.
72479 */
72480
72481 if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(target)) {
72482 DUK_ASSERT(name != NULL);
72483 DUK_TVAL_SET_STRING(&tv_name, name);
72484
72485 found = duk_hobject_hasprop(thr, tv_target, &tv_name);
72486 } else {
72487 /* XXX: duk_hobject_hasprop() would be correct for
72488 * non-Proxy objects too, but it is about ~20-25%
72489 * slower at present so separate code paths for
72490 * Proxy and non-Proxy now.
72491 */
72492 found = duk_hobject_hasprop_raw(thr, target, name);
72493 }
72494
72495 if (found) {
72496 out->value = NULL; /* can't get value, may be accessor */
72497 out->attrs = 0; /* irrelevant when out->value == NULL */
72498 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_THIS(thr));
72499 out->this_binding = tv; /* may be NULL */
72500 out->env = env;
72501 out->holder = target;
72502
72503 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
72504 "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O "
72505 "(object environment record)",
72506 (duk_heaphdr *) name, (duk_tval *) out->value,
72507 (long) out->attrs, (duk_tval *) out->this_binding,
72508 (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
72509 return 1;
72510 }
72511 }
72512
72513 if (!parents) {
72514 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference failed, no parent traversal "
72515 "(not found from first traversed env)"));
72516 goto fail_not_found;
72517 }
72518
72519 if (sanity-- == 0) {
11fdf7f2 72520 DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
7c673cae
FG
72521 }
72522 env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env);
72523 };
72524
72525 /*
72526 * Not found (even in global object)
72527 */
72528
72529 fail_not_found:
72530 return 0;
72531}
72532
72533/*
72534 * HASVAR: check identifier binding from a given environment record
72535 * without traversing its parents.
72536 *
72537 * This primitive is not exposed to user code as such, but is used
72538 * internally for e.g. declaration binding instantiation.
72539 *
72540 * See E5 Sections:
72541 * 10.2.1.1.1 HasBinding(N)
72542 * 10.2.1.2.1 HasBinding(N)
72543 *
72544 * Note: strictness has no bearing on this check. Hence we don't take
72545 * a 'strict' parameter.
72546 */
72547
72548#if 0 /*unused*/
72549DUK_INTERNAL
72550duk_bool_t duk_js_hasvar_envrec(duk_hthread *thr,
72551 duk_hobject *env,
72552 duk_hstring *name) {
72553 duk__id_lookup_result ref;
72554 duk_bool_t parents;
72555
72556 DUK_DDD(DUK_DDDPRINT("hasvar: thr=%p, env=%p, name=%!O "
72557 "(env -> %!dO)",
72558 (void *) thr, (void *) env, (duk_heaphdr *) name,
72559 (duk_heaphdr *) env));
72560
72561 DUK_ASSERT(thr != NULL);
72562 DUK_ASSERT(env != NULL);
72563 DUK_ASSERT(name != NULL);
72564
72565 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env);
72566 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
72567
72568 DUK_ASSERT(DUK_HOBJECT_IS_ENV(env));
72569 DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(env));
72570
72571 /* lookup results is ignored */
72572 parents = 0;
72573 return duk__get_identifier_reference(thr, env, name, NULL, parents, &ref);
72574}
72575#endif
72576
72577/*
72578 * GETVAR
72579 *
72580 * See E5 Sections:
72581 * 11.1.2 Identifier Reference
72582 * 10.3.1 Identifier Resolution
72583 * 11.13.1 Simple Assignment [example of where the Reference is GetValue'd]
72584 * 8.7.1 GetValue (V)
72585 * 8.12.1 [[GetOwnProperty]] (P)
72586 * 8.12.2 [[GetProperty]] (P)
72587 * 8.12.3 [[Get]] (P)
72588 *
72589 * If 'throw' is true, always leaves two values on top of stack: [val this].
72590 *
72591 * If 'throw' is false, returns 0 if identifier cannot be resolved, and the
72592 * stack will be unaffected in this case. If identifier is resolved, returns
72593 * 1 and leaves [val this] on top of stack.
72594 *
72595 * Note: the 'strict' flag of a reference returned by GetIdentifierReference
72596 * is ignored by GetValue. Hence we don't take a 'strict' parameter.
72597 *
72598 * The 'throw' flag is needed for implementing 'typeof' for an unreferenced
72599 * identifier. An unreference identifier in other contexts generates a
72600 * ReferenceError.
72601 */
72602
72603DUK_LOCAL
72604duk_bool_t duk__getvar_helper(duk_hthread *thr,
72605 duk_hobject *env,
72606 duk_activation *act,
72607 duk_hstring *name,
72608 duk_bool_t throw_flag) {
72609 duk_context *ctx = (duk_context *) thr;
72610 duk__id_lookup_result ref;
72611 duk_tval tv_tmp_obj;
72612 duk_tval tv_tmp_key;
72613 duk_bool_t parents;
72614
72615 DUK_DDD(DUK_DDDPRINT("getvar: thr=%p, env=%p, act=%p, name=%!O "
72616 "(env -> %!dO)",
72617 (void *) thr, (void *) env, (void *) act,
72618 (duk_heaphdr *) name, (duk_heaphdr *) env));
72619
72620 DUK_ASSERT(thr != NULL);
72621 DUK_ASSERT(name != NULL);
72622 /* env and act may be NULL */
72623
72624 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env);
72625 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
72626
72627 parents = 1; /* follow parent chain */
72628 if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) {
72629 if (ref.value) {
72630 DUK_ASSERT(ref.this_binding == NULL); /* always for register bindings */
72631 duk_push_tval(ctx, ref.value);
72632 duk_push_undefined(ctx);
72633 } else {
72634 DUK_ASSERT(ref.holder != NULL);
72635
72636 /* Note: getprop may invoke any getter and invalidate any
72637 * duk_tval pointers, so this must be done first.
72638 */
72639
72640 if (ref.this_binding) {
72641 duk_push_tval(ctx, ref.this_binding);
72642 } else {
72643 duk_push_undefined(ctx);
72644 }
72645
72646 DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder);
72647 DUK_TVAL_SET_STRING(&tv_tmp_key, name);
72648 (void) duk_hobject_getprop(thr, &tv_tmp_obj, &tv_tmp_key); /* [this value] */
72649
72650 /* ref.value, ref.this.binding invalidated here by getprop call */
72651
72652 duk_insert(ctx, -2); /* [this value] -> [value this] */
72653 }
72654
72655 return 1;
72656 } else {
72657 if (throw_flag) {
11fdf7f2
TL
72658 DUK_ERROR_FMT1(thr, DUK_ERR_REFERENCE_ERROR,
72659 "identifier '%s' undefined",
72660 (const char *) DUK_HSTRING_GET_DATA(name));
7c673cae
FG
72661 }
72662
72663 return 0;
72664 }
72665}
72666
72667DUK_INTERNAL
72668duk_bool_t duk_js_getvar_envrec(duk_hthread *thr,
72669 duk_hobject *env,
72670 duk_hstring *name,
72671 duk_bool_t throw_flag) {
72672 return duk__getvar_helper(thr, env, NULL, name, throw_flag);
72673}
72674
72675DUK_INTERNAL
72676duk_bool_t duk_js_getvar_activation(duk_hthread *thr,
72677 duk_activation *act,
72678 duk_hstring *name,
72679 duk_bool_t throw_flag) {
72680 DUK_ASSERT(act != NULL);
72681 return duk__getvar_helper(thr, act->lex_env, act, name, throw_flag);
72682}
72683
72684/*
72685 * PUTVAR
72686 *
72687 * See E5 Sections:
72688 * 11.1.2 Identifier Reference
72689 * 10.3.1 Identifier Resolution
72690 * 11.13.1 Simple Assignment [example of where the Reference is PutValue'd]
72691 * 8.7.2 PutValue (V,W) [see especially step 3.b, undefined -> automatic global in non-strict mode]
72692 * 8.12.4 [[CanPut]] (P)
72693 * 8.12.5 [[Put]] (P)
72694 *
72695 * Note: may invalidate any valstack (or object) duk_tval pointers because
72696 * putting a value may reallocate any object or any valstack. Caller beware.
72697 */
72698
72699DUK_LOCAL
72700void duk__putvar_helper(duk_hthread *thr,
72701 duk_hobject *env,
72702 duk_activation *act,
72703 duk_hstring *name,
72704 duk_tval *val,
72705 duk_bool_t strict) {
72706 duk__id_lookup_result ref;
72707 duk_tval tv_tmp_obj;
72708 duk_tval tv_tmp_key;
72709 duk_bool_t parents;
72710
72711 DUK_DDD(DUK_DDDPRINT("putvar: thr=%p, env=%p, act=%p, name=%!O, val=%p, strict=%ld "
72712 "(env -> %!dO, val -> %!T)",
72713 (void *) thr, (void *) env, (void *) act,
72714 (duk_heaphdr *) name, (void *) val, (long) strict,
72715 (duk_heaphdr *) env, (duk_tval *) val));
72716
72717 DUK_ASSERT(thr != NULL);
72718 DUK_ASSERT(name != NULL);
72719 DUK_ASSERT(val != NULL);
72720 /* env and act may be NULL */
72721
72722 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env);
72723 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
72724 DUK_ASSERT_REFCOUNT_NONZERO_TVAL(val);
72725
72726 /*
72727 * In strict mode E5 protects 'eval' and 'arguments' from being
72728 * assigned to (or even declared anywhere). Attempt to do so
72729 * should result in a compile time SyntaxError. See the internal
72730 * design documentation for details.
72731 *
72732 * Thus, we should never come here, run-time, for strict code,
72733 * and name 'eval' or 'arguments'.
72734 */
72735
72736 DUK_ASSERT(!strict ||
72737 (name != DUK_HTHREAD_STRING_EVAL(thr) &&
72738 name != DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)));
72739
72740 /*
72741 * Lookup variable and update in-place if found.
72742 */
72743
72744 parents = 1; /* follow parent chain */
72745
72746 if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) {
72747 if (ref.value && (ref.attrs & DUK_PROPDESC_FLAG_WRITABLE)) {
72748 /* Update duk_tval in-place if pointer provided and the
72749 * property is writable. If the property is not writable
72750 * (immutable binding), use duk_hobject_putprop() which
72751 * will respect mutability.
72752 */
7c673cae
FG
72753 duk_tval *tv_val;
72754
72755 DUK_ASSERT(ref.this_binding == NULL); /* always for register bindings */
72756
72757 tv_val = ref.value;
72758 DUK_ASSERT(tv_val != NULL);
11fdf7f2 72759 DUK_TVAL_SET_TVAL_UPDREF(thr, tv_val, val); /* side effects */
7c673cae
FG
72760
72761 /* ref.value and ref.this_binding invalidated here */
72762 } else {
72763 DUK_ASSERT(ref.holder != NULL);
72764
72765 DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder);
72766 DUK_TVAL_SET_STRING(&tv_tmp_key, name);
72767 (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, val, strict);
72768
72769 /* ref.value and ref.this_binding invalidated here */
72770 }
72771
72772 return;
72773 }
72774
72775 /*
72776 * Not found: write to global object (non-strict) or ReferenceError
72777 * (strict); see E5 Section 8.7.2, step 3.
72778 */
72779
72780 if (strict) {
72781 DUK_DDD(DUK_DDDPRINT("identifier binding not found, strict => reference error"));
72782 DUK_ERROR(thr, DUK_ERR_REFERENCE_ERROR, "identifier not defined");
72783 }
72784
72785 DUK_DDD(DUK_DDDPRINT("identifier binding not found, not strict => set to global"));
72786
72787 DUK_TVAL_SET_OBJECT(&tv_tmp_obj, thr->builtins[DUK_BIDX_GLOBAL]);
72788 DUK_TVAL_SET_STRING(&tv_tmp_key, name);
72789 (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, val, 0); /* 0 = no throw */
72790
72791 /* NB: 'val' may be invalidated here because put_value may realloc valstack,
72792 * caller beware.
72793 */
72794}
72795
72796DUK_INTERNAL
72797void duk_js_putvar_envrec(duk_hthread *thr,
72798 duk_hobject *env,
72799 duk_hstring *name,
72800 duk_tval *val,
72801 duk_bool_t strict) {
72802 duk__putvar_helper(thr, env, NULL, name, val, strict);
72803}
72804
72805DUK_INTERNAL
72806void duk_js_putvar_activation(duk_hthread *thr,
72807 duk_activation *act,
72808 duk_hstring *name,
72809 duk_tval *val,
72810 duk_bool_t strict) {
72811 DUK_ASSERT(act != NULL);
72812 duk__putvar_helper(thr, act->lex_env, act, name, val, strict);
72813}
72814
72815/*
72816 * DELVAR
72817 *
72818 * See E5 Sections:
72819 * 11.4.1 The delete operator
72820 * 10.2.1.1.5 DeleteBinding (N) [declarative environment record]
72821 * 10.2.1.2.5 DeleteBinding (N) [object environment record]
72822 *
72823 * Variable bindings established inside eval() are deletable (configurable),
72824 * other bindings are not, including variables declared in global level.
72825 * Registers are always non-deletable, and the deletion of other bindings
72826 * is controlled by the configurable flag.
72827 *
72828 * For strict mode code, the 'delete' operator should fail with a compile
72829 * time SyntaxError if applied to identifiers. Hence, no strict mode
72830 * run-time deletion of identifiers should ever happen. This function
72831 * should never be called from strict mode code!
72832 */
72833
72834DUK_LOCAL
72835duk_bool_t duk__delvar_helper(duk_hthread *thr,
72836 duk_hobject *env,
72837 duk_activation *act,
72838 duk_hstring *name) {
72839 duk__id_lookup_result ref;
72840 duk_bool_t parents;
72841
72842 DUK_DDD(DUK_DDDPRINT("delvar: thr=%p, env=%p, act=%p, name=%!O "
72843 "(env -> %!dO)",
72844 (void *) thr, (void *) env, (void *) act,
72845 (duk_heaphdr *) name, (duk_heaphdr *) env));
72846
72847 DUK_ASSERT(thr != NULL);
72848 DUK_ASSERT(name != NULL);
72849 /* env and act may be NULL */
72850
72851 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
72852
72853 parents = 1; /* follow parent chain */
72854
72855 if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) {
72856 if (ref.value && !(ref.attrs & DUK_PROPDESC_FLAG_CONFIGURABLE)) {
72857 /* Identifier found in registers (always non-deletable)
72858 * or declarative environment record and non-configurable.
72859 */
72860 return 0;
72861 }
72862 DUK_ASSERT(ref.holder != NULL);
72863
72864 return duk_hobject_delprop_raw(thr, ref.holder, name, 0);
72865 }
72866
72867 /*
72868 * Not found (even in global object).
72869 *
72870 * In non-strict mode this is a silent SUCCESS (!), see E5 Section 11.4.1,
72871 * step 3.b. In strict mode this case is a compile time SyntaxError so
72872 * we should not come here.
72873 */
72874
72875 DUK_DDD(DUK_DDDPRINT("identifier to be deleted not found: name=%!O "
72876 "(treated as silent success)",
72877 (duk_heaphdr *) name));
72878 return 1;
72879}
72880
72881#if 0 /*unused*/
72882DUK_INTERNAL
72883duk_bool_t duk_js_delvar_envrec(duk_hthread *thr,
72884 duk_hobject *env,
72885 duk_hstring *name) {
72886 return duk__delvar_helper(thr, env, NULL, name);
72887}
72888#endif
72889
72890DUK_INTERNAL
72891duk_bool_t duk_js_delvar_activation(duk_hthread *thr,
72892 duk_activation *act,
72893 duk_hstring *name) {
72894 DUK_ASSERT(act != NULL);
72895 return duk__delvar_helper(thr, act->lex_env, act, name);
72896}
72897
72898/*
72899 * DECLVAR
72900 *
72901 * See E5 Sections:
72902 * 10.4.3 Entering Function Code
72903 * 10.5 Declaration Binding Instantion
72904 * 12.2 Variable Statement
72905 * 11.1.2 Identifier Reference
72906 * 10.3.1 Identifier Resolution
72907 *
72908 * Variable declaration behavior is mainly discussed in Section 10.5,
72909 * and is not discussed in the execution semantics (Sections 11-13).
72910 *
72911 * Conceptually declarations happen when code (global, eval, function)
72912 * is entered, before any user code is executed. In practice, register-
72913 * bound identifiers are 'declared' automatically (by virtue of being
72914 * allocated to registers with the initial value 'undefined'). Other
72915 * identifiers are declared in the function prologue with this primitive.
72916 *
72917 * Since non-register bindings eventually back to an internal object's
72918 * properties, the 'prop_flags' argument is used to specify binding
72919 * type:
72920 *
72921 * - Immutable binding: set DUK_PROPDESC_FLAG_WRITABLE to false
72922 * - Non-deletable binding: set DUK_PROPDESC_FLAG_CONFIGURABLE to false
72923 * - The flag DUK_PROPDESC_FLAG_ENUMERABLE should be set, although it
72924 * doesn't really matter for internal objects
72925 *
72926 * All bindings are non-deletable mutable bindings except:
72927 *
72928 * - Declarations in eval code (mutable, deletable)
72929 * - 'arguments' binding in strict function code (immutable)
72930 * - Function name binding of a function expression (immutable)
72931 *
72932 * Declarations may go to declarative environment records (always
72933 * so for functions), but may also go to object environment records
72934 * (e.g. global code). The global object environment has special
72935 * behavior when re-declaring a function (but not a variable); see
72936 * E5.1 specification, Section 10.5, step 5.e.
72937 *
72938 * Declarations always go to the 'top-most' environment record, i.e.
72939 * we never check the record chain. It's not an error even if a
72940 * property (even an immutable or non-deletable one) of the same name
72941 * already exists.
72942 *
72943 * If a declared variable already exists, its value needs to be updated
72944 * (if possible). Returns 1 if a PUTVAR needs to be done by the caller;
72945 * otherwise returns 0.
72946 */
72947
72948DUK_LOCAL
72949duk_bool_t duk__declvar_helper(duk_hthread *thr,
72950 duk_hobject *env,
72951 duk_hstring *name,
72952 duk_tval *val,
72953 duk_small_int_t prop_flags,
72954 duk_bool_t is_func_decl) {
72955 duk_context *ctx = (duk_context *) thr;
72956 duk_hobject *holder;
72957 duk_bool_t parents;
72958 duk__id_lookup_result ref;
72959 duk_tval *tv;
72960
72961 DUK_DDD(DUK_DDDPRINT("declvar: thr=%p, env=%p, name=%!O, val=%!T, prop_flags=0x%08lx, is_func_decl=%ld "
72962 "(env -> %!iO)",
72963 (void *) thr, (void *) env, (duk_heaphdr *) name,
72964 (duk_tval *) val, (unsigned long) prop_flags,
72965 (unsigned int) is_func_decl, (duk_heaphdr *) env));
72966
72967 DUK_ASSERT(thr != NULL);
72968 DUK_ASSERT(env != NULL);
72969 DUK_ASSERT(name != NULL);
72970 DUK_ASSERT(val != NULL);
72971
72972 /* Note: in strict mode the compiler should reject explicit
72973 * declaration of 'eval' or 'arguments'. However, internal
72974 * bytecode may declare 'arguments' in the function prologue.
72975 * We don't bother checking (or asserting) for these now.
72976 */
72977
72978 /* Note: val is a stable duk_tval pointer. The caller makes
72979 * a value copy into its stack frame, so 'tv_val' is not subject
72980 * to side effects here.
72981 */
72982
72983 /*
72984 * Check whether already declared.
72985 *
72986 * We need to check whether the binding exists in the environment
72987 * without walking its parents. However, we still need to check
72988 * register-bound identifiers and the prototype chain of an object
72989 * environment target object.
72990 */
72991
72992 parents = 0; /* just check 'env' */
72993 if (duk__get_identifier_reference(thr, env, name, NULL, parents, &ref)) {
72994 duk_int_t e_idx;
72995 duk_int_t h_idx;
72996 duk_small_int_t flags;
72997
72998 /*
72999 * Variable already declared, ignore re-declaration.
73000 * The only exception is the updated behavior of E5.1 for
73001 * global function declarations, E5.1 Section 10.5, step 5.e.
73002 * This behavior does not apply to global variable declarations.
73003 */
73004
73005 if (!(is_func_decl && env == thr->builtins[DUK_BIDX_GLOBAL_ENV])) {
73006 DUK_DDD(DUK_DDDPRINT("re-declare a binding, ignoring"));
73007 return 1; /* 1 -> needs a PUTVAR */
73008 }
73009
73010 /*
73011 * Special behavior in E5.1.
73012 *
73013 * Note that even though parents == 0, the conflicting property
73014 * may be an inherited property (currently our global object's
73015 * prototype is Object.prototype). Step 5.e first operates on
73016 * the existing property (which is potentially in an ancestor)
73017 * and then defines a new property in the global object (and
73018 * never modifies the ancestor).
73019 *
73020 * Also note that this logic would become even more complicated
73021 * if the conflicting property might be a virtual one. Object
73022 * prototype has no virtual properties, though.
73023 *
73024 * XXX: this is now very awkward, rework.
73025 */
73026
73027 DUK_DDD(DUK_DDDPRINT("re-declare a function binding in global object, "
73028 "updated E5.1 processing"));
73029
73030 DUK_ASSERT(ref.holder != NULL);
73031 holder = ref.holder;
73032
73033 /* holder will be set to the target object, not the actual object
73034 * where the property was found (see duk__get_identifier_reference()).
73035 */
73036 DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(holder) == DUK_HOBJECT_CLASS_GLOBAL);
73037 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(holder)); /* global object doesn't have array part */
73038
73039 /* XXX: use a helper for prototype traversal; no loop check here */
73040 /* must be found: was found earlier, and cannot be inherited */
73041 for (;;) {
73042 DUK_ASSERT(holder != NULL);
73043 duk_hobject_find_existing_entry(thr->heap, holder, name, &e_idx, &h_idx);
73044 if (e_idx >= 0) {
73045 break;
73046 }
73047 /* SCANBUILD: NULL pointer dereference, doesn't actually trigger,
73048 * asserted above.
73049 */
73050 holder = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, holder);
73051 }
73052 DUK_ASSERT(holder != NULL);
73053 DUK_ASSERT(e_idx >= 0);
73054 /* SCANBUILD: scan-build produces a NULL pointer dereference warning
73055 * below; it never actually triggers because holder is actually never
73056 * NULL.
73057 */
73058
73059 /* ref.holder is global object, holder is the object with the
73060 * conflicting property.
73061 */
73062
73063 flags = DUK_HOBJECT_E_GET_FLAGS(thr->heap, holder, e_idx);
73064 if (!(flags & DUK_PROPDESC_FLAG_CONFIGURABLE)) {
73065 if (flags & DUK_PROPDESC_FLAG_ACCESSOR) {
73066 DUK_DDD(DUK_DDDPRINT("existing property is a non-configurable "
73067 "accessor -> reject"));
73068 goto fail_existing_attributes;
73069 }
73070 if (!((flags & DUK_PROPDESC_FLAG_WRITABLE) &&
73071 (flags & DUK_PROPDESC_FLAG_ENUMERABLE))) {
73072 DUK_DDD(DUK_DDDPRINT("existing property is a non-configurable "
73073 "plain property which is not writable and "
73074 "enumerable -> reject"));
73075 goto fail_existing_attributes;
73076 }
73077
73078 DUK_DDD(DUK_DDDPRINT("existing property is not configurable but "
73079 "is plain, enumerable, and writable -> "
73080 "allow redeclaration"));
73081 }
73082
73083 if (holder == ref.holder) {
73084 /* XXX: if duk_hobject_define_property_internal() was updated
73085 * to handle a pre-existing accessor property, this would be
73086 * a simple call (like for the ancestor case).
73087 */
73088 DUK_DDD(DUK_DDDPRINT("redefine, offending property in global object itself"));
73089
73090 if (flags & DUK_PROPDESC_FLAG_ACCESSOR) {
73091 duk_hobject *tmp;
73092
73093 tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, holder, e_idx);
73094 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, holder, e_idx, NULL);
73095 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
73096 DUK_UNREF(tmp);
73097 tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, holder, e_idx);
73098 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, holder, e_idx, NULL);
73099 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
73100 DUK_UNREF(tmp);
73101 } else {
7c673cae 73102 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, holder, e_idx);
11fdf7f2 73103 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv);
7c673cae
FG
73104 }
73105
73106 /* Here val would be potentially invalid if we didn't make
73107 * a value copy at the caller.
73108 */
73109
73110 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, holder, e_idx);
73111 DUK_TVAL_SET_TVAL(tv, val);
73112 DUK_TVAL_INCREF(thr, tv);
73113 DUK_HOBJECT_E_SET_FLAGS(thr->heap, holder, e_idx, prop_flags);
73114
73115 DUK_DDD(DUK_DDDPRINT("updated global binding, final result: "
73116 "value -> %!T, prop_flags=0x%08lx",
73117 (duk_tval *) DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, holder, e_idx),
73118 (unsigned long) prop_flags));
73119 } else {
73120 DUK_DDD(DUK_DDDPRINT("redefine, offending property in ancestor"));
73121
73122 DUK_ASSERT(ref.holder == thr->builtins[DUK_BIDX_GLOBAL]);
73123 duk_push_tval(ctx, val);
73124 duk_hobject_define_property_internal(thr, ref.holder, name, prop_flags);
73125 }
73126
73127 return 0;
73128 }
73129
73130 /*
73131 * Not found (in registers or record objects). Declare
73132 * to current variable environment.
73133 */
73134
73135 /*
73136 * Get holder object
73137 */
73138
73139 if (DUK_HOBJECT_IS_DECENV(env)) {
73140 holder = env;
73141 } else {
73142 DUK_ASSERT(DUK_HOBJECT_IS_OBJENV(env));
73143
73144 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_TARGET(thr));
73145 DUK_ASSERT(tv != NULL);
73146 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
73147 holder = DUK_TVAL_GET_OBJECT(tv);
73148 DUK_ASSERT(holder != NULL);
73149 }
73150
73151 /*
73152 * Define new property
73153 *
73154 * Note: this may fail if the holder is not extensible.
73155 */
73156
73157 /* XXX: this is awkward as we use an internal method which doesn't handle
73158 * extensibility etc correctly. Basically we'd want to do a [[DefineOwnProperty]]
73159 * or Object.defineProperty() here.
73160 */
73161
73162 if (!DUK_HOBJECT_HAS_EXTENSIBLE(holder)) {
73163 goto fail_not_extensible;
73164 }
73165
73166 duk_push_hobject(ctx, holder);
73167 duk_push_hstring(ctx, name);
73168 duk_push_tval(ctx, val);
73169 duk_xdef_prop(ctx, -3, prop_flags); /* [holder name val] -> [holder] */
73170 duk_pop(ctx);
73171
73172 return 0;
73173
73174 fail_existing_attributes:
73175 fail_not_extensible:
11fdf7f2 73176 DUK_ERROR_TYPE(thr, "declaration failed");
7c673cae
FG
73177 return 0;
73178}
73179
73180DUK_INTERNAL
73181duk_bool_t duk_js_declvar_activation(duk_hthread *thr,
73182 duk_activation *act,
73183 duk_hstring *name,
73184 duk_tval *val,
73185 duk_small_int_t prop_flags,
73186 duk_bool_t is_func_decl) {
73187 duk_hobject *env;
73188 duk_tval tv_val_copy;
11fdf7f2
TL
73189 duk_size_t act_off;
73190
73191 DUK_ASSERT(act != NULL);
73192 act_off = (duk_size_t) ((duk_uint8_t *) act - (duk_uint8_t *) thr->callstack);
7c673cae
FG
73193
73194 /*
73195 * Make a value copy of the input val. This ensures that
73196 * side effects cannot invalidate the pointer.
73197 */
73198
73199 DUK_TVAL_SET_TVAL(&tv_val_copy, val);
73200 val = &tv_val_copy;
73201
73202 /*
73203 * Delayed env creation check
73204 */
73205
73206 if (!act->var_env) {
73207 DUK_ASSERT(act->lex_env == NULL);
73208 duk_js_init_activation_environment_records_delayed(thr, act);
11fdf7f2 73209 act = (duk_activation *) ((duk_uint8_t *) thr->callstack + act_off);
7c673cae
FG
73210 }
73211 DUK_ASSERT(act->lex_env != NULL);
73212 DUK_ASSERT(act->var_env != NULL);
73213
73214 env = act->var_env;
73215 DUK_ASSERT(env != NULL);
73216 DUK_ASSERT(DUK_HOBJECT_IS_ENV(env));
73217
73218 return duk__declvar_helper(thr, env, name, val, prop_flags, is_func_decl);
73219}
7c673cae
FG
73220/*
73221 * Lexer for source files, ToNumber() string conversions, RegExp expressions,
73222 * and JSON.
73223 *
73224 * Provides a stream of Ecmascript tokens from an UTF-8/CESU-8 buffer. The
73225 * caller can also rewind the token stream into a certain position which is
73226 * needed by the compiler part for multi-pass scanning. Tokens are
73227 * represented as duk_token structures, and contain line number information.
73228 * Token types are identified with DUK_TOK_* defines.
73229 *
73230 * Characters are decoded into a fixed size lookup window consisting of
73231 * decoded Unicode code points, with window positions past the end of the
73232 * input filled with an invalid codepoint (-1). The tokenizer can thus
73233 * perform multiple character lookups efficiently and with few sanity
73234 * checks (such as access outside the end of the input), which keeps the
73235 * tokenization code small at the cost of performance.
73236 *
73237 * Character data in tokens, such as identifier names and string literals,
73238 * is encoded into CESU-8 format on-the-fly while parsing the token in
73239 * question. The string data is made reachable to garbage collection by
73240 * placing the token-related values in value stack entries allocated for
73241 * this purpose by the caller. The characters exist in Unicode code point
73242 * form only in the fixed size lookup window, which keeps character data
73243 * expansion (of especially ASCII data) low.
73244 *
73245 * Token parsing supports the full range of Unicode characters as described
73246 * in the E5 specification. Parsing has been optimized for ASCII characters
73247 * because ordinary Ecmascript code consists almost entirely of ASCII
73248 * characters. Matching of complex Unicode codepoint sets (such as in the
73249 * IdentifierStart and IdentifierPart productions) is optimized for size,
73250 * and is done using a linear scan of a bit-packed list of ranges. This is
73251 * very slow, but should never be entered unless the source code actually
73252 * contains Unicode characters.
73253 *
73254 * Ecmascript tokenization is partially context sensitive. First,
73255 * additional future reserved words are recognized in strict mode (see E5
73256 * Section 7.6.1.2). Second, a forward slash character ('/') can be
73257 * recognized either as starting a RegExp literal or as a division operator,
73258 * depending on context. The caller must provide necessary context flags
73259 * when requesting a new token.
73260 *
73261 * Future work:
73262 *
73263 * * Make line number tracking optional, as it consumes space.
73264 *
73265 * * Add a feature flag for disabling UTF-8 decoding of input, as most
73266 * source code is ASCII. Because of Unicode escapes written in ASCII,
73267 * this does not allow Unicode support to be removed from e.g.
73268 * duk_unicode_is_identifier_start() nor does it allow removal of CESU-8
73269 * encoding of e.g. string literals.
73270 *
73271 * * Add a feature flag for disabling Unicode compliance of e.g. identifier
73272 * names. This allows for a build more than a kilobyte smaller, because
73273 * Unicode ranges needed by duk_unicode_is_identifier_start() and
73274 * duk_unicode_is_identifier_part() can be dropped. String literals
73275 * should still be allowed to contain escaped Unicode, so this still does
73276 * not allow removal of CESU-8 encoding of e.g. string literals.
73277 *
73278 * * Character lookup tables for codepoints above BMP could be stripped.
73279 *
73280 * * Strictly speaking, E5 specification requires that source code consists
73281 * of 16-bit code units, and if not, must be conceptually converted to
73282 * that format first. The current lexer processes Unicode code points
73283 * and allows characters outside the BMP. These should be converted to
73284 * surrogate pairs while reading the source characters into the window,
73285 * not after tokens have been formed (as is done now). However, the fix
73286 * is not trivial because two characters are decoded from one codepoint.
73287 *
73288 * * Optimize for speed as well as size. Large if-else ladders are (at
73289 * least potentially) slow.
73290 */
73291
73292/* include removed: duk_internal.h */
73293
73294/*
73295 * Various defines and file specific helper macros
73296 */
73297
73298#define DUK__MAX_RE_DECESC_DIGITS 9
73299#define DUK__MAX_RE_QUANT_DIGITS 9 /* Does not allow e.g. 2**31-1, but one more would allow overflows of u32. */
73300
73301/* whether to use macros or helper function depends on call count */
73302#define DUK__ISDIGIT(x) ((x) >= DUK_ASC_0 && (x) <= DUK_ASC_9)
73303#define DUK__ISHEXDIGIT(x) duk__is_hex_digit((x))
73304#define DUK__ISOCTDIGIT(x) ((x) >= DUK_ASC_0 && (x) <= DUK_ASC_7)
73305#define DUK__ISDIGIT03(x) ((x) >= DUK_ASC_0 && (x) <= DUK_ASC_3)
73306#define DUK__ISDIGIT47(x) ((x) >= DUK_ASC_4 && (x) <= DUK_ASC_7)
73307
73308/* lexer character window helpers */
73309#define DUK__LOOKUP(lex_ctx,index) ((lex_ctx)->window[(index)].codepoint)
73310#define DUK__ADVANCECHARS(lex_ctx,count) duk__advance_bytes((lex_ctx), (count) * sizeof(duk_lexer_codepoint))
73311#define DUK__ADVANCEBYTES(lex_ctx,count) duk__advance_bytes((lex_ctx), (count))
73312#define DUK__INITBUFFER(lex_ctx) duk__initbuffer((lex_ctx))
73313#define DUK__APPENDBUFFER(lex_ctx,x) duk__appendbuffer((lex_ctx), (duk_codepoint_t) (x))
73314
73315/* lookup shorthands (note: assume context variable is named 'lex_ctx') */
73316#define DUK__L0() DUK__LOOKUP(lex_ctx, 0)
73317#define DUK__L1() DUK__LOOKUP(lex_ctx, 1)
73318#define DUK__L2() DUK__LOOKUP(lex_ctx, 2)
73319#define DUK__L3() DUK__LOOKUP(lex_ctx, 3)
73320#define DUK__L4() DUK__LOOKUP(lex_ctx, 4)
73321#define DUK__L5() DUK__LOOKUP(lex_ctx, 5)
73322
73323/* packed advance/token number macro used by multiple functions */
73324#define DUK__ADVTOK(advbytes,tok) ((((advbytes) * sizeof(duk_lexer_codepoint)) << 8) + (tok))
73325
73326/*
73327 * Advance lookup window by N characters, filling in new characters as
73328 * necessary. After returning caller is guaranteed a character window of
73329 * at least DUK_LEXER_WINDOW_SIZE characters.
73330 *
73331 * The main function duk__advance_bytes() is called at least once per every
73332 * token so it has a major lexer/compiler performance impact. There are two
73333 * variants for the main duk__advance_bytes() algorithm: a sliding window
73334 * approach which is slightly faster at the cost of larger code footprint,
73335 * and a simple copying one.
73336 *
73337 * Decoding directly from the source string would be another lexing option.
73338 * But the lookup window based approach has the advantage of hiding the
73339 * source string and its encoding effectively which gives more flexibility
73340 * going forward to e.g. support chunked streaming of source from flash.
73341 *
73342 * Decodes UTF-8/CESU-8 leniently with support for code points from U+0000 to
73343 * U+10FFFF, causing an error if the input is unparseable. Leniency means:
73344 *
73345 * * Unicode code point validation is intentionally not performed,
73346 * except to check that the codepoint does not exceed 0x10ffff.
73347 *
73348 * * In particular, surrogate pairs are allowed and not combined, which
73349 * allows source files to represent all SourceCharacters with CESU-8.
73350 * Broken surrogate pairs are allowed, as Ecmascript does not mandate
73351 * their validation.
73352 *
73353 * * Allow non-shortest UTF-8 encodings.
73354 *
73355 * Leniency here causes few security concerns because all character data is
73356 * decoded into Unicode codepoints before lexer processing, and is then
73357 * re-encoded into CESU-8. The source can be parsed as strict UTF-8 with
73358 * a compiler option. However, Ecmascript source characters include -all-
73359 * 16-bit unsigned integer codepoints, so leniency seems to be appropriate.
73360 *
73361 * Note that codepoints above the BMP are not strictly SourceCharacters,
73362 * but the lexer still accepts them as such. Before ending up in a string
73363 * or an identifier name, codepoints above BMP are converted into surrogate
73364 * pairs and then CESU-8 encoded, resulting in 16-bit Unicode data as
73365 * expected by Ecmascript.
73366 *
73367 * An alternative approach to dealing with invalid or partial sequences
73368 * would be to skip them and replace them with e.g. the Unicode replacement
73369 * character U+FFFD. This has limited utility because a replacement character
73370 * will most likely cause a parse error, unless it occurs inside a string.
73371 * Further, Ecmascript source is typically pure ASCII.
73372 *
73373 * See:
73374 *
73375 * http://en.wikipedia.org/wiki/UTF-8
73376 * http://en.wikipedia.org/wiki/CESU-8
73377 * http://tools.ietf.org/html/rfc3629
73378 * http://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences
73379 *
73380 * Future work:
73381 *
73382 * * Reject other invalid Unicode sequences (see Wikipedia entry for examples)
73383 * in strict UTF-8 mode.
73384 *
73385 * * Size optimize. An attempt to use a 16-byte lookup table for the first
73386 * byte resulted in a code increase though.
73387 *
73388 * * Is checking against maximum 0x10ffff really useful? 4-byte encoding
73389 * imposes a certain limit anyway.
73390 *
73391 * * Support chunked streaming of source code. Can be implemented either
73392 * by streaming chunks of bytes or chunks of codepoints.
73393 */
73394
73395#if defined(DUK_USE_LEXER_SLIDING_WINDOW)
73396DUK_LOCAL void duk__fill_lexer_buffer(duk_lexer_ctx *lex_ctx, duk_small_uint_t start_offset_bytes) {
73397 duk_lexer_codepoint *cp, *cp_end;
73398 duk_ucodepoint_t x;
73399 duk_small_uint_t contlen;
73400 const duk_uint8_t *p, *p_end;
11fdf7f2 73401#if defined(DUK_USE_STRICT_UTF8_SOURCE)
7c673cae
FG
73402 duk_ucodepoint_t mincp;
73403#endif
73404 duk_int_t input_line;
73405
73406 /* Use temporaries and update lex_ctx only when finished. */
73407 input_line = lex_ctx->input_line;
73408 p = lex_ctx->input + lex_ctx->input_offset;
73409 p_end = lex_ctx->input + lex_ctx->input_length;
73410
73411 cp = (duk_lexer_codepoint *) (void *) ((duk_uint8_t *) lex_ctx->buffer + start_offset_bytes);
73412 cp_end = lex_ctx->buffer + DUK_LEXER_BUFFER_SIZE;
73413
73414 for (; cp != cp_end; cp++) {
73415 cp->offset = (duk_size_t) (p - lex_ctx->input);
73416 cp->line = input_line;
73417
73418 /* XXX: potential issue with signed pointers, p_end < p. */
73419 if (DUK_UNLIKELY(p >= p_end)) {
73420 /* If input_offset were assigned a negative value, it would
73421 * result in a large positive value. Most likely it would be
73422 * larger than input_length and be caught here. In any case
73423 * no memory unsafe behavior would happen.
73424 */
73425 cp->codepoint = -1;
73426 continue;
73427 }
73428
73429 x = (duk_ucodepoint_t) (*p++);
73430
73431 /* Fast path. */
73432
73433 if (DUK_LIKELY(x < 0x80UL)) {
73434 DUK_ASSERT(x != 0x2028UL && x != 0x2029UL); /* not LS/PS */
73435 if (DUK_UNLIKELY(x <= 0x000dUL)) {
73436 if ((x == 0x000aUL) ||
73437 ((x == 0x000dUL) && (p >= p_end || *p != 0x000aUL))) {
73438 /* lookup for 0x000a above assumes shortest encoding now */
73439
73440 /* E5 Section 7.3, treat the following as newlines:
73441 * LF
73442 * CR [not followed by LF]
73443 * LS
73444 * PS
73445 *
73446 * For CR LF, CR is ignored if it is followed by LF, and the LF will bump
73447 * the line number.
73448 */
73449 input_line++;
73450 }
73451 }
73452
73453 cp->codepoint = (duk_codepoint_t) x;
73454 continue;
73455 }
73456
73457 /* Slow path. */
73458
73459 if (x < 0xc0UL) {
73460 /* 10xx xxxx -> invalid */
73461 goto error_encoding;
73462 } else if (x < 0xe0UL) {
73463 /* 110x xxxx 10xx xxxx */
73464 contlen = 1;
11fdf7f2 73465#if defined(DUK_USE_STRICT_UTF8_SOURCE)
7c673cae
FG
73466 mincp = 0x80UL;
73467#endif
73468 x = x & 0x1fUL;
73469 } else if (x < 0xf0UL) {
73470 /* 1110 xxxx 10xx xxxx 10xx xxxx */
73471 contlen = 2;
11fdf7f2 73472#if defined(DUK_USE_STRICT_UTF8_SOURCE)
7c673cae
FG
73473 mincp = 0x800UL;
73474#endif
73475 x = x & 0x0fUL;
73476 } else if (x < 0xf8UL) {
73477 /* 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx */
73478 contlen = 3;
11fdf7f2 73479#if defined(DUK_USE_STRICT_UTF8_SOURCE)
7c673cae
FG
73480 mincp = 0x10000UL;
73481#endif
73482 x = x & 0x07UL;
73483 } else {
73484 /* no point in supporting encodings of 5 or more bytes */
73485 goto error_encoding;
73486 }
73487
73488 DUK_ASSERT(p_end >= p);
73489 if ((duk_size_t) contlen > (duk_size_t) (p_end - p)) {
73490 goto error_clipped;
73491 }
73492
73493 while (contlen > 0) {
73494 duk_small_uint_t y;
73495 y = *p++;
73496 if ((y & 0xc0U) != 0x80U) {
73497 /* check that byte has the form 10xx xxxx */
73498 goto error_encoding;
73499 }
73500 x = x << 6;
73501 x += y & 0x3fUL;
73502 contlen--;
73503 }
73504
73505 /* check final character validity */
73506
73507 if (x > 0x10ffffUL) {
73508 goto error_encoding;
73509 }
11fdf7f2 73510#if defined(DUK_USE_STRICT_UTF8_SOURCE)
7c673cae
FG
73511 if (x < mincp || (x >= 0xd800UL && x <= 0xdfffUL) || x == 0xfffeUL) {
73512 goto error_encoding;
73513 }
73514#endif
73515
73516 DUK_ASSERT(x != 0x000aUL && x != 0x000dUL);
73517 if ((x == 0x2028UL) || (x == 0x2029UL)) {
73518 input_line++;
73519 }
73520
73521 cp->codepoint = (duk_codepoint_t) x;
73522 }
73523
73524 lex_ctx->input_offset = (duk_size_t) (p - lex_ctx->input);
73525 lex_ctx->input_line = input_line;
73526 return;
73527
73528 error_clipped: /* clipped codepoint */
73529 error_encoding: /* invalid codepoint encoding or codepoint */
73530 lex_ctx->input_offset = (duk_size_t) (p - lex_ctx->input);
73531 lex_ctx->input_line = input_line;
73532
11fdf7f2 73533 DUK_ERROR_SYNTAX(lex_ctx->thr, "utf-8 decode failed");
7c673cae
FG
73534}
73535
73536DUK_LOCAL void duk__advance_bytes(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_bytes) {
73537 duk_small_uint_t used_bytes, avail_bytes;
73538
73539 DUK_ASSERT_DISABLE(count_bytes >= 0); /* unsigned */
73540 DUK_ASSERT(count_bytes <= (duk_small_uint_t) (DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint)));
73541 DUK_ASSERT(lex_ctx->window >= lex_ctx->buffer);
73542 DUK_ASSERT(lex_ctx->window < lex_ctx->buffer + DUK_LEXER_BUFFER_SIZE);
73543 DUK_ASSERT((duk_uint8_t *) lex_ctx->window + count_bytes <= (duk_uint8_t *) lex_ctx->buffer + DUK_LEXER_BUFFER_SIZE * sizeof(duk_lexer_codepoint));
73544
73545 /* Zero 'count' is also allowed to make call sites easier.
73546 * Arithmetic in bytes generates better code in GCC.
73547 */
73548
73549 lex_ctx->window = (duk_lexer_codepoint *) (void *) ((duk_uint8_t *) lex_ctx->window + count_bytes); /* avoid multiply */
73550 used_bytes = (duk_small_uint_t) ((duk_uint8_t *) lex_ctx->window - (duk_uint8_t *) lex_ctx->buffer);
73551 avail_bytes = DUK_LEXER_BUFFER_SIZE * sizeof(duk_lexer_codepoint) - used_bytes;
73552 if (avail_bytes < (duk_small_uint_t) (DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint))) {
73553 /* Not enough data to provide a full window, so "scroll" window to
73554 * start of buffer and fill up the rest.
73555 */
73556 DUK_MEMMOVE((void *) lex_ctx->buffer,
73557 (const void *) lex_ctx->window,
73558 (size_t) avail_bytes);
73559 lex_ctx->window = lex_ctx->buffer;
73560 duk__fill_lexer_buffer(lex_ctx, avail_bytes);
73561 }
73562}
73563
73564DUK_LOCAL void duk__init_lexer_window(duk_lexer_ctx *lex_ctx) {
73565 lex_ctx->window = lex_ctx->buffer;
73566 duk__fill_lexer_buffer(lex_ctx, 0);
73567}
73568#else /* DUK_USE_LEXER_SLIDING_WINDOW */
73569DUK_LOCAL duk_codepoint_t duk__read_char(duk_lexer_ctx *lex_ctx) {
73570 duk_ucodepoint_t x;
73571 duk_small_uint_t len;
73572 duk_small_uint_t i;
73573 const duk_uint8_t *p;
11fdf7f2 73574#if defined(DUK_USE_STRICT_UTF8_SOURCE)
7c673cae
FG
73575 duk_ucodepoint_t mincp;
73576#endif
73577 duk_size_t input_offset;
73578
73579 input_offset = lex_ctx->input_offset;
73580 if (DUK_UNLIKELY(input_offset >= lex_ctx->input_length)) {
73581 /* If input_offset were assigned a negative value, it would
73582 * result in a large positive value. Most likely it would be
73583 * larger than input_length and be caught here. In any case
73584 * no memory unsafe behavior would happen.
73585 */
73586 return -1;
73587 }
73588
73589 p = lex_ctx->input + input_offset;
73590 x = (duk_ucodepoint_t) (*p);
73591
73592 if (DUK_LIKELY(x < 0x80UL)) {
73593 /* 0xxx xxxx -> fast path */
73594
73595 /* input offset tracking */
73596 lex_ctx->input_offset++;
73597
73598 DUK_ASSERT(x != 0x2028UL && x != 0x2029UL); /* not LS/PS */
73599 if (DUK_UNLIKELY(x <= 0x000dUL)) {
73600 if ((x == 0x000aUL) ||
73601 ((x == 0x000dUL) && (lex_ctx->input_offset >= lex_ctx->input_length ||
73602 lex_ctx->input[lex_ctx->input_offset] != 0x000aUL))) {
73603 /* lookup for 0x000a above assumes shortest encoding now */
73604
73605 /* E5 Section 7.3, treat the following as newlines:
73606 * LF
73607 * CR [not followed by LF]
73608 * LS
73609 * PS
73610 *
73611 * For CR LF, CR is ignored if it is followed by LF, and the LF will bump
73612 * the line number.
73613 */
73614 lex_ctx->input_line++;
73615 }
73616 }
73617
73618 return (duk_codepoint_t) x;
73619 }
73620
73621 /* Slow path. */
73622
73623 if (x < 0xc0UL) {
73624 /* 10xx xxxx -> invalid */
73625 goto error_encoding;
73626 } else if (x < 0xe0UL) {
73627 /* 110x xxxx 10xx xxxx */
73628 len = 2;
11fdf7f2 73629#if defined(DUK_USE_STRICT_UTF8_SOURCE)
7c673cae
FG
73630 mincp = 0x80UL;
73631#endif
73632 x = x & 0x1fUL;
73633 } else if (x < 0xf0UL) {
73634 /* 1110 xxxx 10xx xxxx 10xx xxxx */
73635 len = 3;
11fdf7f2 73636#if defined(DUK_USE_STRICT_UTF8_SOURCE)
7c673cae
FG
73637 mincp = 0x800UL;
73638#endif
73639 x = x & 0x0fUL;
73640 } else if (x < 0xf8UL) {
73641 /* 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx */
73642 len = 4;
11fdf7f2 73643#if defined(DUK_USE_STRICT_UTF8_SOURCE)
7c673cae
FG
73644 mincp = 0x10000UL;
73645#endif
73646 x = x & 0x07UL;
73647 } else {
73648 /* no point in supporting encodings of 5 or more bytes */
73649 goto error_encoding;
73650 }
73651
73652 DUK_ASSERT(lex_ctx->input_length >= lex_ctx->input_offset);
73653 if ((duk_size_t) len > (duk_size_t) (lex_ctx->input_length - lex_ctx->input_offset)) {
73654 goto error_clipped;
73655 }
73656
73657 p++;
73658 for (i = 1; i < len; i++) {
73659 duk_small_uint_t y;
73660 y = *p++;
73661 if ((y & 0xc0U) != 0x80U) {
73662 /* check that byte has the form 10xx xxxx */
73663 goto error_encoding;
73664 }
73665 x = x << 6;
73666 x += y & 0x3fUL;
73667 }
73668
73669 /* check final character validity */
73670
73671 if (x > 0x10ffffUL) {
73672 goto error_encoding;
73673 }
11fdf7f2 73674#if defined(DUK_USE_STRICT_UTF8_SOURCE)
7c673cae
FG
73675 if (x < mincp || (x >= 0xd800UL && x <= 0xdfffUL) || x == 0xfffeUL) {
73676 goto error_encoding;
73677 }
73678#endif
73679
73680 /* input offset tracking */
73681 lex_ctx->input_offset += len;
73682
73683 /* line tracking */
73684 DUK_ASSERT(x != 0x000aUL && x != 0x000dUL);
73685 if ((x == 0x2028UL) || (x == 0x2029UL)) {
73686 lex_ctx->input_line++;
73687 }
73688
73689 return (duk_codepoint_t) x;
73690
73691 error_clipped: /* clipped codepoint */
73692 error_encoding: /* invalid codepoint encoding or codepoint */
11fdf7f2 73693 DUK_ERROR_SYNTAX(lex_ctx->thr, "utf-8 decode failed");
7c673cae
FG
73694 return 0;
73695}
73696
73697DUK_LOCAL void duk__advance_bytes(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_bytes) {
73698 duk_small_uint_t keep_bytes;
73699 duk_lexer_codepoint *cp, *cp_end;
73700
73701 DUK_ASSERT_DISABLE(count_bytes >= 0); /* unsigned */
73702 DUK_ASSERT(count_bytes <= (duk_small_uint_t) (DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint)));
73703
73704 /* Zero 'count' is also allowed to make call sites easier. */
73705
73706 keep_bytes = DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint) - count_bytes;
73707 DUK_MEMMOVE((void *) lex_ctx->window,
73708 (const void *) ((duk_uint8_t *) lex_ctx->window + count_bytes),
11fdf7f2 73709 (size_t) keep_bytes);
7c673cae
FG
73710
73711 cp = (duk_lexer_codepoint *) ((duk_uint8_t *) lex_ctx->window + keep_bytes);
73712 cp_end = lex_ctx->window + DUK_LEXER_WINDOW_SIZE;
73713 for (; cp != cp_end; cp++) {
73714 cp->offset = lex_ctx->input_offset;
73715 cp->line = lex_ctx->input_line;
73716 cp->codepoint = duk__read_char(lex_ctx);
73717 }
73718}
73719
73720DUK_LOCAL void duk__init_lexer_window(duk_lexer_ctx *lex_ctx) {
73721 /* Call with count == DUK_LEXER_WINDOW_SIZE to fill buffer initially. */
73722 duk__advance_bytes(lex_ctx, DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint)); /* fill window */
73723}
73724#endif /* DUK_USE_LEXER_SLIDING_WINDOW */
73725
73726/*
73727 * (Re)initialize the temporary byte buffer. May be called extra times
73728 * with little impact.
73729 */
73730
73731DUK_LOCAL void duk__initbuffer(duk_lexer_ctx *lex_ctx) {
73732 /* Reuse buffer as is unless buffer has grown large. */
73733 if (DUK_HBUFFER_DYNAMIC_GET_SIZE(lex_ctx->buf) < DUK_LEXER_TEMP_BUF_LIMIT) {
73734 /* Keep current size */
73735 } else {
73736 duk_hbuffer_resize(lex_ctx->thr, lex_ctx->buf, DUK_LEXER_TEMP_BUF_LIMIT);
73737 }
73738
73739 DUK_BW_INIT_WITHBUF(lex_ctx->thr, &lex_ctx->bw, lex_ctx->buf);
73740}
73741
73742/*
73743 * Append a Unicode codepoint to the temporary byte buffer. Performs
73744 * CESU-8 surrogate pair encoding for codepoints above the BMP.
73745 * Existing surrogate pairs are allowed and also encoded into CESU-8.
73746 */
73747
73748DUK_LOCAL void duk__appendbuffer(duk_lexer_ctx *lex_ctx, duk_codepoint_t x) {
73749 /*
73750 * Since character data is only generated by decoding the source or by
73751 * the compiler itself, we rely on the input codepoints being correct
73752 * and avoid a check here.
73753 *
73754 * Character data can also come here through decoding of Unicode
73755 * escapes ("\udead\ubeef") so all 16-but unsigned values can be
73756 * present, even when the source file itself is strict UTF-8.
73757 */
73758
73759 DUK_ASSERT(x >= 0 && x <= 0x10ffff);
73760
73761 DUK_BW_WRITE_ENSURE_CESU8(lex_ctx->thr, &lex_ctx->bw, (duk_ucodepoint_t) x);
73762}
73763
73764/*
73765 * Intern the temporary byte buffer into a valstack slot
73766 * (in practice, slot1 or slot2).
73767 */
73768
73769DUK_LOCAL void duk__internbuffer(duk_lexer_ctx *lex_ctx, duk_idx_t valstack_idx) {
73770 duk_context *ctx = (duk_context *) lex_ctx->thr;
73771
73772 DUK_ASSERT(valstack_idx == lex_ctx->slot1_idx || valstack_idx == lex_ctx->slot2_idx);
73773
73774 DUK_BW_PUSH_AS_STRING(lex_ctx->thr, &lex_ctx->bw);
73775 duk_replace(ctx, valstack_idx);
73776}
73777
73778/*
73779 * Init lexer context
73780 */
73781
73782DUK_INTERNAL void duk_lexer_initctx(duk_lexer_ctx *lex_ctx) {
73783 DUK_ASSERT(lex_ctx != NULL);
73784
73785 DUK_MEMZERO(lex_ctx, sizeof(*lex_ctx));
11fdf7f2 73786#if defined(DUK_USE_EXPLICIT_NULL_INIT)
7c673cae
FG
73787#if defined(DUK_USE_LEXER_SLIDING_WINDOW)
73788 lex_ctx->window = NULL;
73789#endif
73790 lex_ctx->thr = NULL;
73791 lex_ctx->input = NULL;
73792 lex_ctx->buf = NULL;
73793#endif
73794}
73795
73796/*
73797 * Set lexer input position and reinitialize lookup window.
73798 */
73799
73800/* NB: duk_lexer_getpoint() is a macro only */
73801
73802DUK_INTERNAL void duk_lexer_setpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt) {
73803 DUK_ASSERT_DISABLE(pt->offset >= 0); /* unsigned */
73804 DUK_ASSERT(pt->line >= 1);
73805 lex_ctx->input_offset = pt->offset;
73806 lex_ctx->input_line = pt->line;
73807 duk__init_lexer_window(lex_ctx);
73808}
73809
73810/*
73811 * Lexing helpers
73812 */
73813
73814/* numeric value of a hex digit (also covers octal and decimal digits) */
73815DUK_LOCAL duk_codepoint_t duk__hexval(duk_lexer_ctx *lex_ctx, duk_codepoint_t x) {
73816 duk_small_int_t t;
73817
73818 /* Here 'x' is a Unicode codepoint */
73819 if (DUK_LIKELY(x >= 0 && x <= 0xff)) {
73820 t = duk_hex_dectab[x];
73821 if (DUK_LIKELY(t >= 0)) {
73822 return t;
73823 }
73824 }
73825
73826 /* Throwing an error this deep makes the error rather vague, but
73827 * saves hundreds of bytes of code.
73828 */
11fdf7f2 73829 DUK_ERROR_SYNTAX(lex_ctx->thr, "decode error");
7c673cae
FG
73830 return 0;
73831}
73832
73833/* having this as a separate function provided a size benefit */
73834DUK_LOCAL duk_bool_t duk__is_hex_digit(duk_codepoint_t x) {
73835 if (DUK_LIKELY(x >= 0 && x <= 0xff)) {
73836 return (duk_hex_dectab[x] >= 0);
73837 }
73838 return 0;
73839}
73840
73841DUK_LOCAL duk_codepoint_t duk__decode_hexesc_from_window(duk_lexer_ctx *lex_ctx, duk_small_int_t lookup_offset) {
73842 /* validation performed by duk__hexval */
73843 return (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset].codepoint) << 4) |
73844 (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset + 1].codepoint));
73845}
73846
73847DUK_LOCAL duk_codepoint_t duk__decode_uniesc_from_window(duk_lexer_ctx *lex_ctx, duk_small_int_t lookup_offset) {
73848 /* validation performed by duk__hexval */
73849 return (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset].codepoint) << 12) |
73850 (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset + 1].codepoint) << 8) |
73851 (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset + 2].codepoint) << 4) |
73852 (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset + 3].codepoint));
73853}
73854
73855/*
73856 * Parse Ecmascript source InputElementDiv or InputElementRegExp
73857 * (E5 Section 7), skipping whitespace, comments, and line terminators.
73858 *
73859 * Possible results are:
73860 * (1) a token
73861 * (2) a line terminator (skipped)
73862 * (3) a comment (skipped)
73863 * (4) EOF
73864 *
73865 * White space is automatically skipped from the current position (but
73866 * not after the input element). If input has already ended, returns
73867 * DUK_TOK_EOF indefinitely. If a parse error occurs, uses an DUK_ERROR()
73868 * macro call (and hence a longjmp through current heap longjmp context).
73869 * Comments and line terminator tokens are automatically skipped.
73870 *
73871 * The input element being matched is determined by regexp_mode; if set,
73872 * parses a InputElementRegExp, otherwise a InputElementDiv. The
73873 * difference between these are handling of productions starting with a
73874 * forward slash.
73875 *
73876 * If strict_mode is set, recognizes additional future reserved words
73877 * specific to strict mode, and refuses to parse octal literals.
73878 *
73879 * The matching strategy below is to (currently) use a six character
73880 * lookup window to quickly determine which production is the -longest-
73881 * matching one, and then parse that. The top-level if-else clauses
73882 * match the first character, and the code blocks for each clause
73883 * handle -all- alternatives for that first character. Ecmascript
73884 * specification uses the "longest match wins" semantics, so the order
73885 * of the if-clauses matters.
73886 *
73887 * Misc notes:
73888 *
73889 * * Ecmascript numeric literals do not accept a sign character.
73890 * Consequently e.g. "-1.0" is parsed as two tokens: a negative
73891 * sign and a positive numeric literal. The compiler performs
73892 * the negation during compilation, so this has no adverse impact.
73893 *
73894 * * There is no token for "undefined": it is just a value available
73895 * from the global object (or simply established by doing a reference
73896 * to an undefined value).
73897 *
73898 * * Some contexts want Identifier tokens, which are IdentifierNames
73899 * excluding reserved words, while some contexts want IdentifierNames
73900 * directly. In the latter case e.g. "while" is interpreted as an
73901 * identifier name, not a DUK_TOK_WHILE token. The solution here is
73902 * to provide both token types: DUK_TOK_WHILE goes to 't' while
73903 * DUK_TOK_IDENTIFIER goes to 't_nores', and 'slot1' always contains
73904 * the identifier / keyword name.
73905 *
73906 * * Directive prologue needs to identify string literals such as
73907 * "use strict" and 'use strict', which are sensitive to line
73908 * continuations and escape sequences. For instance, "use\u0020strict"
73909 * is a valid directive but is distinct from "use strict". The solution
73910 * here is to decode escapes while tokenizing, but to keep track of the
73911 * number of escapes. Directive detection can then check that the
73912 * number of escapes is zero.
73913 *
73914 * * Multi-line comments with one or more internal LineTerminator are
73915 * treated like a line terminator to comply with automatic semicolon
73916 * insertion.
73917 */
73918
73919DUK_INTERNAL
73920void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
73921 duk_token *out_token,
73922 duk_bool_t strict_mode,
73923 duk_bool_t regexp_mode) {
73924 duk_codepoint_t x; /* temporary, must be signed and 32-bit to hold Unicode code points */
73925 duk_small_uint_t advtok = 0; /* (advance << 8) + token_type, updated at function end,
73926 * init is unnecessary but suppresses "may be used uninitialized" warnings.
73927 */
73928 duk_bool_t got_lineterm = 0; /* got lineterm preceding non-whitespace, non-lineterm token */
73929
73930 if (++lex_ctx->token_count >= lex_ctx->token_limit) {
11fdf7f2 73931 DUK_ERROR_RANGE(lex_ctx->thr, "token limit");
7c673cae
FG
73932 return; /* unreachable */
73933 }
73934
73935 out_token->t = DUK_TOK_EOF;
73936 out_token->t_nores = -1; /* marker: copy t if not changed */
73937#if 0 /* not necessary to init, disabled for faster parsing */
73938 out_token->num = DUK_DOUBLE_NAN;
73939 out_token->str1 = NULL;
73940 out_token->str2 = NULL;
73941#endif
73942 out_token->num_escapes = 0;
73943 /* out_token->lineterm set by caller */
73944
73945 /* This would be nice, but parsing is faster without resetting the
73946 * value slots. The only side effect is that references to temporary
73947 * string values may linger until lexing is finished; they're then
73948 * freed normally.
73949 */
73950#if 0
73951 duk_to_undefined((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
73952 duk_to_undefined((duk_context *) lex_ctx->thr, lex_ctx->slot2_idx);
73953#endif
73954
73955 /* 'advtok' indicates how much to advance and which token id to assign
73956 * at the end. This shared functionality minimizes code size. All
73957 * code paths are required to set 'advtok' to some value, so no default
73958 * init value is used. Code paths calling DUK_ERROR() never return so
73959 * they don't need to set advtok.
73960 */
73961
73962 /*
73963 * Matching order:
73964 *
73965 * Punctuator first chars, also covers comments, regexps
73966 * LineTerminator
73967 * Identifier or reserved word, also covers null/true/false literals
73968 * NumericLiteral
73969 * StringLiteral
73970 * EOF
73971 *
73972 * The order does not matter as long as the longest match is
73973 * always correctly identified. There are order dependencies
73974 * in the clauses, so it's not trivial to convert to a switch.
73975 */
73976
73977 restart_lineupdate:
73978 out_token->start_line = lex_ctx->window[0].line;
73979
73980 restart:
73981 out_token->start_offset = lex_ctx->window[0].offset;
73982
73983 x = DUK__L0();
73984
73985 switch (x) {
73986 case DUK_ASC_SPACE:
73987 case DUK_ASC_HT: /* fast paths for space and tab */
73988 DUK__ADVANCECHARS(lex_ctx, 1);
73989 goto restart;
73990 case DUK_ASC_LF: /* LF line terminator; CR LF and Unicode lineterms are handled in slow path */
73991 DUK__ADVANCECHARS(lex_ctx, 1);
73992 got_lineterm = 1;
73993 goto restart_lineupdate;
73994 case DUK_ASC_SLASH: /* '/' */
73995 if (DUK__L1() == '/') {
73996 /*
73997 * E5 Section 7.4, allow SourceCharacter (which is any 16-bit
73998 * code point).
73999 */
74000
74001 /* DUK__ADVANCECHARS(lex_ctx, 2) would be correct here, but it unnecessary */
74002 for (;;) {
74003 x = DUK__L0();
74004 if (x < 0 || duk_unicode_is_line_terminator(x)) {
74005 break;
74006 }
74007 DUK__ADVANCECHARS(lex_ctx, 1);
74008 }
74009 goto restart; /* line terminator will be handled on next round */
74010 } else if (DUK__L1() == '*') {
74011 /*
74012 * E5 Section 7.4. If the multi-line comment contains a newline,
74013 * it is treated like a single line terminator for automatic
74014 * semicolon insertion.
74015 */
74016
74017 duk_bool_t last_asterisk = 0;
74018 DUK__ADVANCECHARS(lex_ctx, 2);
74019 for (;;) {
74020 x = DUK__L0();
74021 if (x < 0) {
11fdf7f2 74022 DUK_ERROR_SYNTAX(lex_ctx->thr, "eof in multiline comment");
7c673cae
FG
74023 }
74024 DUK__ADVANCECHARS(lex_ctx, 1);
74025 if (last_asterisk && x == '/') {
74026 break;
74027 }
74028 if (duk_unicode_is_line_terminator(x)) {
74029 got_lineterm = 1;
74030 }
74031 last_asterisk = (x == '*');
74032 }
74033 goto restart_lineupdate;
74034 } else if (regexp_mode) {
11fdf7f2 74035#if defined(DUK_USE_REGEXP_SUPPORT)
7c673cae
FG
74036 /*
74037 * "/" followed by something in regexp mode. See E5 Section 7.8.5.
74038 *
74039 * RegExp parsing is a bit complex. First, the regexp body is delimited
74040 * by forward slashes, but the body may also contain forward slashes as
74041 * part of an escape sequence or inside a character class (delimited by
74042 * square brackets). A mini state machine is used to implement these.
74043 *
74044 * Further, an early (parse time) error must be thrown if the regexp
74045 * would cause a run-time error when used in the expression new RegExp(...).
74046 * Parsing here simply extracts the (candidate) regexp, and also accepts
74047 * invalid regular expressions (which are delimited properly). The caller
74048 * (compiler) must perform final validation and regexp compilation.
74049 *
74050 * RegExp first char may not be '/' (single line comment) or '*' (multi-
74051 * line comment). These have already been checked above, so there is no
74052 * need below for special handling of the first regexp character as in
74053 * the E5 productions.
74054 *
74055 * About unicode escapes within regexp literals:
74056 *
74057 * E5 Section 7.8.5 grammar does NOT accept \uHHHH escapes.
74058 * However, Section 6 states that regexps accept the escapes,
74059 * see paragraph starting with "In string literals...".
74060 * The regexp grammar, which sees the decoded regexp literal
74061 * (after lexical parsing) DOES have a \uHHHH unicode escape.
74062 * So, for instance:
74063 *
74064 * /\u1234/
74065 *
74066 * should first be parsed by the lexical grammar as:
74067 *
74068 * '\' 'u' RegularExpressionBackslashSequence
74069 * '1' RegularExpressionNonTerminator
74070 * '2' RegularExpressionNonTerminator
74071 * '3' RegularExpressionNonTerminator
74072 * '4' RegularExpressionNonTerminator
74073 *
74074 * and the escape itself is then parsed by the regexp engine.
74075 * This is the current implementation.
74076 *
74077 * Minor spec inconsistency:
74078 *
74079 * E5 Section 7.8.5 RegularExpressionBackslashSequence is:
74080 *
74081 * \ RegularExpressionNonTerminator
74082 *
74083 * while Section A.1 RegularExpressionBackslashSequence is:
74084 *
74085 * \ NonTerminator
74086 *
74087 * The latter is not normative and a typo.
74088 *
74089 */
74090
74091 /* first, parse regexp body roughly */
74092
74093 duk_small_int_t state = 0; /* 0=base, 1=esc, 2=class, 3=class+esc */
74094
74095 DUK__INITBUFFER(lex_ctx);
74096 for (;;) {
74097 DUK__ADVANCECHARS(lex_ctx, 1); /* skip opening slash on first loop */
74098 x = DUK__L0();
74099 if (x < 0 || duk_unicode_is_line_terminator(x)) {
11fdf7f2 74100 DUK_ERROR_SYNTAX(lex_ctx->thr, "eof or line terminator in regexp");
7c673cae
FG
74101 }
74102 x = DUK__L0(); /* re-read to avoid spill / fetch */
74103 if (state == 0) {
74104 if (x == '/') {
74105 DUK__ADVANCECHARS(lex_ctx, 1); /* eat closing slash */
74106 break;
74107 } else if (x == '\\') {
74108 state = 1;
74109 } else if (x == '[') {
74110 state = 2;
74111 }
74112 } else if (state == 1) {
74113 state = 0;
74114 } else if (state == 2) {
74115 if (x == ']') {
74116 state = 0;
74117 } else if (x == '\\') {
74118 state = 3;
74119 }
74120 } else { /* state == 3 */
74121 state = 2;
74122 }
74123 DUK__APPENDBUFFER(lex_ctx, x);
74124 }
74125 duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
74126 out_token->str1 = duk_get_hstring((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
74127
74128 /* second, parse flags */
74129
74130 DUK__INITBUFFER(lex_ctx);
74131 for (;;) {
74132 x = DUK__L0();
74133 if (!duk_unicode_is_identifier_part(x)) {
74134 break;
74135 }
74136 x = DUK__L0(); /* re-read to avoid spill / fetch */
74137 DUK__APPENDBUFFER(lex_ctx, x);
74138 DUK__ADVANCECHARS(lex_ctx, 1);
74139 }
74140 duk__internbuffer(lex_ctx, lex_ctx->slot2_idx);
74141 out_token->str2 = duk_get_hstring((duk_context *) lex_ctx->thr, lex_ctx->slot2_idx);
74142
74143 DUK__INITBUFFER(lex_ctx); /* free some memory */
74144
74145 /* validation of the regexp is caller's responsibility */
74146
74147 advtok = DUK__ADVTOK(0, DUK_TOK_REGEXP);
74148#else
11fdf7f2 74149 DUK_ERROR_SYNTAX(lex_ctx->thr, "regexp support disabled");
7c673cae
FG
74150#endif
74151 } else if (DUK__L1() == '=') {
74152 /* "/=" and not in regexp mode */
74153 advtok = DUK__ADVTOK(2, DUK_TOK_DIV_EQ);
74154 } else {
74155 /* "/" and not in regexp mode */
74156 advtok = DUK__ADVTOK(1, DUK_TOK_DIV);
74157 }
74158 break;
74159 case DUK_ASC_LCURLY: /* '{' */
74160 advtok = DUK__ADVTOK(1, DUK_TOK_LCURLY);
74161 break;
74162 case DUK_ASC_RCURLY: /* '}' */
74163 advtok = DUK__ADVTOK(1, DUK_TOK_RCURLY);
74164 break;
74165 case DUK_ASC_LPAREN: /* '(' */
74166 advtok = DUK__ADVTOK(1, DUK_TOK_LPAREN);
74167 break;
74168 case DUK_ASC_RPAREN: /* ')' */
74169 advtok = DUK__ADVTOK(1, DUK_TOK_RPAREN);
74170 break;
74171 case DUK_ASC_LBRACKET: /* '[' */
74172 advtok = DUK__ADVTOK(1, DUK_TOK_LBRACKET);
74173 break;
74174 case DUK_ASC_RBRACKET: /* ']' */
74175 advtok = DUK__ADVTOK(1, DUK_TOK_RBRACKET);
74176 break;
74177 case DUK_ASC_PERIOD: /* '.' */
74178 if (DUK__ISDIGIT(DUK__L1())) {
74179 /* Period followed by a digit can only start DecimalLiteral
74180 * (handled in slow path). We could jump straight into the
74181 * DecimalLiteral handling but should avoid goto to inside
74182 * a block.
74183 */
74184 goto slow_path;
74185 }
74186 advtok = DUK__ADVTOK(1, DUK_TOK_PERIOD);
74187 break;
74188 case DUK_ASC_SEMICOLON: /* ';' */
74189 advtok = DUK__ADVTOK(1, DUK_TOK_SEMICOLON);
74190 break;
74191 case DUK_ASC_COMMA: /* ',' */
74192 advtok = DUK__ADVTOK(1, DUK_TOK_COMMA);
74193 break;
74194 case DUK_ASC_LANGLE: /* '<' */
74195 if (DUK__L1() == '<' && DUK__L2() == '=') {
74196 advtok = DUK__ADVTOK(3, DUK_TOK_ALSHIFT_EQ);
74197 } else if (DUK__L1() == '=') {
74198 advtok = DUK__ADVTOK(2, DUK_TOK_LE);
74199 } else if (DUK__L1() == '<') {
74200 advtok = DUK__ADVTOK(2, DUK_TOK_ALSHIFT);
74201 } else {
74202 advtok = DUK__ADVTOK(1, DUK_TOK_LT);
74203 }
74204 break;
74205 case DUK_ASC_RANGLE: /* '>' */
74206 if (DUK__L1() == '>' && DUK__L2() == '>' && DUK__L3() == '=') {
74207 advtok = DUK__ADVTOK(4, DUK_TOK_RSHIFT_EQ);
74208 } else if (DUK__L1() == '>' && DUK__L2() == '>') {
74209 advtok = DUK__ADVTOK(3, DUK_TOK_RSHIFT);
74210 } else if (DUK__L1() == '>' && DUK__L2() == '=') {
74211 advtok = DUK__ADVTOK(3, DUK_TOK_ARSHIFT_EQ);
74212 } else if (DUK__L1() == '=') {
74213 advtok = DUK__ADVTOK(2, DUK_TOK_GE);
74214 } else if (DUK__L1() == '>') {
74215 advtok = DUK__ADVTOK(2, DUK_TOK_ARSHIFT);
74216 } else {
74217 advtok = DUK__ADVTOK(1, DUK_TOK_GT);
74218 }
74219 break;
74220 case DUK_ASC_EQUALS: /* '=' */
74221 if (DUK__L1() == '=' && DUK__L2() == '=') {
74222 advtok = DUK__ADVTOK(3, DUK_TOK_SEQ);
74223 } else if (DUK__L1() == '=') {
74224 advtok = DUK__ADVTOK(2, DUK_TOK_EQ);
74225 } else {
74226 advtok = DUK__ADVTOK(1, DUK_TOK_EQUALSIGN);
74227 }
74228 break;
74229 case DUK_ASC_EXCLAMATION: /* '!' */
74230 if (DUK__L1() == '=' && DUK__L2() == '=') {
74231 advtok = DUK__ADVTOK(3, DUK_TOK_SNEQ);
74232 } else if (DUK__L1() == '=') {
74233 advtok = DUK__ADVTOK(2, DUK_TOK_NEQ);
74234 } else {
74235 advtok = DUK__ADVTOK(1, DUK_TOK_LNOT);
74236 }
74237 break;
74238 case DUK_ASC_PLUS: /* '+' */
74239 if (DUK__L1() == '+') {
74240 advtok = DUK__ADVTOK(2, DUK_TOK_INCREMENT);
74241 } else if (DUK__L1() == '=') {
74242 advtok = DUK__ADVTOK(2, DUK_TOK_ADD_EQ);
74243 } else {
74244 advtok = DUK__ADVTOK(1, DUK_TOK_ADD);
74245 }
74246 break;
74247 case DUK_ASC_MINUS: /* '-' */
74248 if (DUK__L1() == '-') {
74249 advtok = DUK__ADVTOK(2, DUK_TOK_DECREMENT);
74250 } else if (DUK__L1() == '=') {
74251 advtok = DUK__ADVTOK(2, DUK_TOK_SUB_EQ);
74252 } else {
74253 advtok = DUK__ADVTOK(1, DUK_TOK_SUB);
74254 }
74255 break;
74256 case DUK_ASC_STAR: /* '*' */
74257 if (DUK__L1() == '=') {
74258 advtok = DUK__ADVTOK(2, DUK_TOK_MUL_EQ);
74259 } else {
74260 advtok = DUK__ADVTOK(1, DUK_TOK_MUL);
74261 }
74262 break;
74263 case DUK_ASC_PERCENT: /* '%' */
74264 if (DUK__L1() == '=') {
74265 advtok = DUK__ADVTOK(2, DUK_TOK_MOD_EQ);
74266 } else {
74267 advtok = DUK__ADVTOK(1, DUK_TOK_MOD);
74268 }
74269 break;
74270 case DUK_ASC_AMP: /* '&' */
74271 if (DUK__L1() == '&') {
74272 advtok = DUK__ADVTOK(2, DUK_TOK_LAND);
74273 } else if (DUK__L1() == '=') {
74274 advtok = DUK__ADVTOK(2, DUK_TOK_BAND_EQ);
74275 } else {
74276 advtok = DUK__ADVTOK(1, DUK_TOK_BAND);
74277 }
74278 break;
74279 case DUK_ASC_PIPE: /* '|' */
74280 if (DUK__L1() == '|') {
74281 advtok = DUK__ADVTOK(2, DUK_TOK_LOR);
74282 } else if (DUK__L1() == '=') {
74283 advtok = DUK__ADVTOK(2, DUK_TOK_BOR_EQ);
74284 } else {
74285 advtok = DUK__ADVTOK(1, DUK_TOK_BOR);
74286 }
74287 break;
74288 case DUK_ASC_CARET: /* '^' */
74289 if (DUK__L1() == '=') {
74290 advtok = DUK__ADVTOK(2, DUK_TOK_BXOR_EQ);
74291 } else {
74292 advtok = DUK__ADVTOK(1, DUK_TOK_BXOR);
74293 }
74294 break;
74295 case DUK_ASC_TILDE: /* '~' */
74296 advtok = DUK__ADVTOK(1, DUK_TOK_BNOT);
74297 break;
74298 case DUK_ASC_QUESTION: /* '?' */
74299 advtok = DUK__ADVTOK(1, DUK_TOK_QUESTION);
74300 break;
74301 case DUK_ASC_COLON: /* ':' */
74302 advtok = DUK__ADVTOK(1, DUK_TOK_COLON);
74303 break;
74304 case DUK_ASC_DOUBLEQUOTE: /* '"' */
74305 case DUK_ASC_SINGLEQUOTE: { /* '\'' */
74306 duk_small_int_t quote = x; /* Note: duk_uint8_t type yields larger code */
74307 duk_small_int_t adv;
74308
74309 DUK__INITBUFFER(lex_ctx);
74310 for (;;) {
74311 DUK__ADVANCECHARS(lex_ctx, 1); /* eat opening quote on first loop */
74312 x = DUK__L0();
74313 if (x < 0 || duk_unicode_is_line_terminator(x)) {
11fdf7f2 74314 DUK_ERROR_SYNTAX(lex_ctx->thr, "eof or line terminator in string literal");
7c673cae
FG
74315 }
74316 if (x == quote) {
74317 DUK__ADVANCECHARS(lex_ctx, 1); /* eat closing quote */
74318 break;
74319 }
74320 if (x == '\\') {
74321 /* DUK__L0 -> '\' char
74322 * DUK__L1 ... DUK__L5 -> more lookup
74323 */
74324
74325 x = DUK__L1();
74326
74327 /* How much to advance before next loop; note that next loop
74328 * will advance by 1 anyway, so -1 from the total escape
74329 * length (e.g. len('\uXXXX') - 1 = 6 - 1). As a default,
74330 * 1 is good.
74331 */
74332 adv = 2 - 1; /* note: long live range */
74333
74334 if (x < 0) {
11fdf7f2 74335 DUK_ERROR_SYNTAX(lex_ctx->thr, "eof or line terminator in string literal");
7c673cae
FG
74336 }
74337 if (duk_unicode_is_line_terminator(x)) {
74338 /* line continuation */
74339 if (x == 0x000d && DUK__L2() == 0x000a) {
74340 /* CR LF again a special case */
74341 adv = 3 - 1;
74342 }
74343 } else if (x == '\'') {
74344 DUK__APPENDBUFFER(lex_ctx, 0x0027);
74345 } else if (x == '"') {
74346 DUK__APPENDBUFFER(lex_ctx, 0x0022);
74347 } else if (x == '\\') {
74348 DUK__APPENDBUFFER(lex_ctx, 0x005c);
74349 } else if (x == 'b') {
74350 DUK__APPENDBUFFER(lex_ctx, 0x0008);
74351 } else if (x == 'f') {
74352 DUK__APPENDBUFFER(lex_ctx, 0x000c);
74353 } else if (x == 'n') {
74354 DUK__APPENDBUFFER(lex_ctx, 0x000a);
74355 } else if (x == 'r') {
74356 DUK__APPENDBUFFER(lex_ctx, 0x000d);
74357 } else if (x == 't') {
74358 DUK__APPENDBUFFER(lex_ctx, 0x0009);
74359 } else if (x == 'v') {
74360 DUK__APPENDBUFFER(lex_ctx, 0x000b);
74361 } else if (x == 'x') {
74362 adv = 4 - 1;
74363 DUK__APPENDBUFFER(lex_ctx, duk__decode_hexesc_from_window(lex_ctx, 2));
74364 } else if (x == 'u') {
74365 adv = 6 - 1;
74366 DUK__APPENDBUFFER(lex_ctx, duk__decode_uniesc_from_window(lex_ctx, 2));
74367 } else if (DUK__ISDIGIT(x)) {
74368 duk_codepoint_t ch = 0; /* initialized to avoid warnings of unused var */
74369
74370 /*
74371 * Octal escape or zero escape:
74372 * \0 (lookahead not DecimalDigit)
74373 * \1 ... \7 (lookahead not DecimalDigit)
74374 * \ZeroToThree OctalDigit (lookahead not DecimalDigit)
74375 * \FourToSeven OctalDigit (no lookahead restrictions)
74376 * \ZeroToThree OctalDigit OctalDigit (no lookahead restrictions)
74377 *
74378 * Zero escape is part of the standard syntax. Octal escapes are
74379 * defined in E5 Section B.1.2, and are only allowed in non-strict mode.
74380 * Any other productions starting with a decimal digit are invalid.
74381 */
74382
74383 if (x == '0' && !DUK__ISDIGIT(DUK__L2())) {
74384 /* Zero escape (also allowed in non-strict mode) */
74385 ch = 0;
74386 /* adv = 2 - 1 default OK */
11fdf7f2 74387#if defined(DUK_USE_OCTAL_SUPPORT)
7c673cae
FG
74388 } else if (strict_mode) {
74389 /* No other escape beginning with a digit in strict mode */
11fdf7f2 74390 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid escape in string literal");
7c673cae
FG
74391 } else if (DUK__ISDIGIT03(x) && DUK__ISOCTDIGIT(DUK__L2()) && DUK__ISOCTDIGIT(DUK__L3())) {
74392 /* Three digit octal escape, digits validated. */
74393 adv = 4 - 1;
74394 ch = (duk__hexval(lex_ctx, x) << 6) +
74395 (duk__hexval(lex_ctx, DUK__L2()) << 3) +
74396 duk__hexval(lex_ctx, DUK__L3());
74397 } else if (((DUK__ISDIGIT03(x) && !DUK__ISDIGIT(DUK__L3())) || DUK__ISDIGIT47(x)) &&
74398 DUK__ISOCTDIGIT(DUK__L2())) {
74399 /* Two digit octal escape, digits validated.
74400 *
74401 * The if-condition is a bit tricky. We could catch e.g.
74402 * '\039' in the three-digit escape and fail it there (by
74403 * validating the digits), but we want to avoid extra
74404 * additional validation code.
74405 */
74406 adv = 3 - 1;
74407 ch = (duk__hexval(lex_ctx, x) << 3) +
74408 duk__hexval(lex_ctx, DUK__L2());
74409 } else if (DUK__ISDIGIT(x) && !DUK__ISDIGIT(DUK__L2())) {
74410 /* One digit octal escape, digit validated. */
74411 /* adv = 2 default OK */
74412 ch = duk__hexval(lex_ctx, x);
74413#else
74414 /* fall through to error */
74415#endif
74416 } else {
11fdf7f2 74417 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid escape in string literal");
7c673cae
FG
74418 }
74419
74420 DUK__APPENDBUFFER(lex_ctx, ch);
74421 } else {
74422 /* escaped NonEscapeCharacter */
74423 DUK__APPENDBUFFER(lex_ctx, x);
74424 }
74425 DUK__ADVANCECHARS(lex_ctx, adv);
74426
74427 /* Track number of escapes; count not really needed but directive
74428 * prologues need to detect whether there were any escapes or line
74429 * continuations or not.
74430 */
74431 out_token->num_escapes++;
74432 } else {
74433 /* part of string */
74434 DUK__APPENDBUFFER(lex_ctx, x);
74435 }
74436 }
74437
74438 duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
74439 out_token->str1 = duk_get_hstring((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
74440
74441 DUK__INITBUFFER(lex_ctx); /* free some memory */
74442
74443 advtok = DUK__ADVTOK(0, DUK_TOK_STRING);
74444 break;
74445 }
74446 default:
74447 goto slow_path;
74448 } /* switch */
74449
74450 goto skip_slow_path;
74451
74452 slow_path:
74453 if (duk_unicode_is_line_terminator(x)) {
74454 if (x == 0x000d && DUK__L1() == 0x000a) {
74455 /*
74456 * E5 Section 7.3: CR LF is detected as a single line terminator for
74457 * line numbers. Here we also detect it as a single line terminator
74458 * token.
74459 */
74460 DUK__ADVANCECHARS(lex_ctx, 2);
74461 } else {
74462 DUK__ADVANCECHARS(lex_ctx, 1);
74463 }
74464 got_lineterm = 1;
74465 goto restart_lineupdate;
74466 } else if (duk_unicode_is_identifier_start(x) || x == '\\') {
74467 /*
74468 * Parse an identifier and then check whether it is:
74469 * - reserved word (keyword or other reserved word)
74470 * - "null" (NullLiteral)
74471 * - "true" (BooleanLiteral)
74472 * - "false" (BooleanLiteral)
74473 * - anything else => identifier
74474 *
74475 * This does not follow the E5 productions cleanly, but is
74476 * useful and compact.
74477 *
74478 * Note that identifiers may contain Unicode escapes,
74479 * see E5 Sections 6 and 7.6. They must be decoded first,
74480 * and the result checked against allowed characters.
74481 * The above if-clause accepts an identifier start and an
74482 * '\' character -- no other token can begin with a '\'.
74483 *
74484 * Note that "get" and "set" are not reserved words in E5
74485 * specification so they are recognized as plain identifiers
74486 * (the tokens DUK_TOK_GET and DUK_TOK_SET are actually not
74487 * used now). The compiler needs to work around this.
74488 *
74489 * Strictly speaking, following Ecmascript longest match
74490 * specification, an invalid escape for the first character
74491 * should cause a syntax error. However, an invalid escape
74492 * for IdentifierParts should just terminate the identifier
74493 * early (longest match), and let the next tokenization
74494 * fail. For instance Rhino croaks with 'foo\z' when
74495 * parsing the identifier. This has little practical impact.
74496 */
74497
74498 duk_small_int_t i, i_end;
74499 duk_bool_t first = 1;
74500 duk_hstring *str;
74501
74502 DUK__INITBUFFER(lex_ctx);
74503 for (;;) {
74504 /* re-lookup first char on first loop */
74505 if (DUK__L0() == '\\') {
74506 duk_codepoint_t ch;
74507 if (DUK__L1() != 'u') {
11fdf7f2 74508 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid unicode escape in identifier");
7c673cae
FG
74509 }
74510
74511 ch = duk__decode_uniesc_from_window(lex_ctx, 2);
74512
74513 /* IdentifierStart is stricter than IdentifierPart, so if the first
74514 * character is escaped, must have a stricter check here.
74515 */
74516 if (!(first ? duk_unicode_is_identifier_start(ch) : duk_unicode_is_identifier_part(ch))) {
11fdf7f2 74517 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid unicode escape in identifier");
7c673cae
FG
74518 }
74519 DUK__APPENDBUFFER(lex_ctx, ch);
74520 DUK__ADVANCECHARS(lex_ctx, 6);
74521
74522 /* Track number of escapes: necessary for proper keyword
74523 * detection.
74524 */
74525 out_token->num_escapes++;
74526 } else {
74527 /* Note: first character is checked against this. But because
74528 * IdentifierPart includes all IdentifierStart characters, and
74529 * the first character (if unescaped) has already been checked
74530 * in the if condition, this is OK.
74531 */
74532 if (!duk_unicode_is_identifier_part(DUK__L0())) {
74533 break;
74534 }
74535 DUK__APPENDBUFFER(lex_ctx, DUK__L0());
74536 DUK__ADVANCECHARS(lex_ctx, 1);
74537 }
74538 first = 0;
74539 }
74540
74541 duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
74542 out_token->str1 = duk_get_hstring((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
74543 str = out_token->str1;
74544 DUK_ASSERT(str != NULL);
74545 out_token->t_nores = DUK_TOK_IDENTIFIER;
74546
74547 DUK__INITBUFFER(lex_ctx); /* free some memory */
74548
74549 /*
74550 * Interned identifier is compared against reserved words, which are
11fdf7f2 74551 * currently interned into the heap context. See genbuiltins.py.
7c673cae
FG
74552 *
74553 * Note that an escape in the identifier disables recognition of
74554 * keywords; e.g. "\u0069f = 1;" is a valid statement (assigns to
74555 * identifier named "if"). This is not necessarily compliant,
74556 * see test-dec-escaped-char-in-keyword.js.
74557 *
74558 * Note: "get" and "set" are awkward. They are not officially
74559 * ReservedWords (and indeed e.g. "var set = 1;" is valid), and
74560 * must come out as DUK_TOK_IDENTIFIER. The compiler needs to
74561 * work around this a bit.
74562 */
74563
74564 /* XXX: optimize by adding the token numbers directly into the
74565 * always interned duk_hstring objects (there should be enough
74566 * flag bits free for that)?
74567 */
74568
74569 i_end = (strict_mode ? DUK_STRIDX_END_RESERVED : DUK_STRIDX_START_STRICT_RESERVED);
74570
74571 advtok = DUK__ADVTOK(0, DUK_TOK_IDENTIFIER);
74572 if (out_token->num_escapes == 0) {
74573 for (i = DUK_STRIDX_START_RESERVED; i < i_end; i++) {
74574 DUK_ASSERT(i >= 0 && i < DUK_HEAP_NUM_STRINGS);
74575 if (DUK_HTHREAD_GET_STRING(lex_ctx->thr, i) == str) {
74576 advtok = DUK__ADVTOK(0, DUK_STRIDX_TO_TOK(i));
74577 break;
74578 }
74579 }
74580 }
74581 } else if (DUK__ISDIGIT(x) || (x == '.')) {
74582 /* Note: decimal number may start with a period, but must be followed by a digit */
74583
74584 /*
74585 * DecimalLiteral, HexIntegerLiteral, OctalIntegerLiteral
74586 * "pre-parsing", followed by an actual, accurate parser step.
74587 *
74588 * Note: the leading sign character ('+' or '-') is -not- part of
74589 * the production in E5 grammar, and that the a DecimalLiteral
74590 * starting with a '0' must be followed by a non-digit. Leading
74591 * zeroes are syntax errors and must be checked for.
74592 *
74593 * XXX: the two step parsing process is quite awkward, it would
74594 * be more straightforward to allow numconv to parse the longest
74595 * valid prefix (it already does that, it only needs to indicate
74596 * where the input ended). However, the lexer decodes characters
74597 * using a lookup window, so this is not a trivial change.
74598 */
74599
74600 /* XXX: because of the final check below (that the literal is not
74601 * followed by a digit), this could maybe be simplified, if we bail
74602 * out early from a leading zero (and if there are no periods etc).
74603 * Maybe too complex.
74604 */
74605
74606 duk_double_t val;
74607 duk_bool_t int_only = 0;
74608 duk_bool_t allow_hex = 0;
74609 duk_small_int_t state; /* 0=before period/exp,
74610 * 1=after period, before exp
74611 * 2=after exp, allow '+' or '-'
74612 * 3=after exp and exp sign
74613 */
74614 duk_small_uint_t s2n_flags;
74615 duk_codepoint_t y;
74616
74617 DUK__INITBUFFER(lex_ctx);
74618 y = DUK__L1();
74619 if (x == '0' && (y == 'x' || y == 'X')) {
74620 DUK__APPENDBUFFER(lex_ctx, x);
74621 DUK__APPENDBUFFER(lex_ctx, y);
74622 DUK__ADVANCECHARS(lex_ctx, 2);
74623 int_only = 1;
74624 allow_hex = 1;
11fdf7f2 74625#if defined(DUK_USE_OCTAL_SUPPORT)
7c673cae
FG
74626 } else if (!strict_mode && x == '0' && DUK__ISDIGIT(y)) {
74627 /* Note: if DecimalLiteral starts with a '0', it can only be
74628 * followed by a period or an exponent indicator which starts
74629 * with 'e' or 'E'. Hence the if-check above ensures that
74630 * OctalIntegerLiteral is the only valid NumericLiteral
74631 * alternative at this point (even if y is, say, '9').
74632 */
74633
74634 DUK__APPENDBUFFER(lex_ctx, x);
74635 DUK__ADVANCECHARS(lex_ctx, 1);
74636 int_only = 1;
74637#endif
74638 }
74639
74640 state = 0;
74641 for (;;) {
74642 x = DUK__L0(); /* re-lookup curr char on first round */
74643 if (DUK__ISDIGIT(x)) {
74644 /* Note: intentionally allow leading zeroes here, as the
74645 * actual parser will check for them.
74646 */
74647 if (state == 2) {
74648 state = 3;
74649 }
74650 } else if (allow_hex && DUK__ISHEXDIGIT(x)) {
74651 /* Note: 'e' and 'E' are also accepted here. */
74652 ;
74653 } else if (x == '.') {
74654 if (state >= 1 || int_only) {
74655 break;
74656 } else {
74657 state = 1;
74658 }
74659 } else if (x == 'e' || x == 'E') {
74660 if (state >= 2 || int_only) {
74661 break;
74662 } else {
74663 state = 2;
74664 }
74665 } else if (x == '-' || x == '+') {
74666 if (state != 2) {
74667 break;
74668 } else {
74669 state = 3;
74670 }
74671 } else {
74672 break;
74673 }
74674 DUK__APPENDBUFFER(lex_ctx, x);
74675 DUK__ADVANCECHARS(lex_ctx, 1);
74676 }
74677
74678 /* XXX: better coercion */
74679 duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
74680
74681 s2n_flags = DUK_S2N_FLAG_ALLOW_EXP |
74682 DUK_S2N_FLAG_ALLOW_FRAC |
74683 DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
74684 DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
11fdf7f2 74685#if defined(DUK_USE_OCTAL_SUPPORT)
7c673cae
FG
74686 (strict_mode ? 0 : DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT) |
74687#endif
74688 DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT;
74689
74690 duk_dup((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
74691 duk_numconv_parse((duk_context *) lex_ctx->thr, 10 /*radix*/, s2n_flags);
74692 val = duk_to_number((duk_context *) lex_ctx->thr, -1);
74693 if (DUK_ISNAN(val)) {
11fdf7f2 74694 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid numeric literal");
7c673cae
FG
74695 }
74696 duk_replace((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx); /* could also just pop? */
74697
74698 DUK__INITBUFFER(lex_ctx); /* free some memory */
74699
74700 /* Section 7.8.3 (note): NumericLiteral must be followed by something other than
74701 * IdentifierStart or DecimalDigit.
74702 */
74703
74704 if (DUK__ISDIGIT(DUK__L0()) || duk_unicode_is_identifier_start(DUK__L0())) {
11fdf7f2 74705 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid numeric literal");
7c673cae
FG
74706 }
74707
74708 out_token->num = val;
74709 advtok = DUK__ADVTOK(0, DUK_TOK_NUMBER);
74710 } else if (duk_unicode_is_whitespace(DUK__LOOKUP(lex_ctx, 0))) {
74711 DUK__ADVANCECHARS(lex_ctx, 1);
74712 goto restart;
74713 } else if (x < 0) {
74714 advtok = DUK__ADVTOK(0, DUK_TOK_EOF);
74715 } else {
11fdf7f2 74716 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid token");
7c673cae
FG
74717 }
74718 skip_slow_path:
74719
74720 /*
74721 * Shared exit path
74722 */
74723
74724 DUK__ADVANCEBYTES(lex_ctx, advtok >> 8);
74725 out_token->t = advtok & 0xff;
74726 if (out_token->t_nores < 0) {
74727 out_token->t_nores = out_token->t;
74728 }
74729 out_token->lineterm = got_lineterm;
74730
74731 /* Automatic semicolon insertion is allowed if a token is preceded
74732 * by line terminator(s), or terminates a statement list (right curly
74733 * or EOF).
74734 */
74735 if (got_lineterm || out_token->t == DUK_TOK_RCURLY || out_token->t == DUK_TOK_EOF) {
74736 out_token->allow_auto_semi = 1;
74737 } else {
74738 out_token->allow_auto_semi = 0;
74739 }
74740}
74741
11fdf7f2 74742#if defined(DUK_USE_REGEXP_SUPPORT)
7c673cae
FG
74743
74744/*
74745 * Parse a RegExp token. The grammar is described in E5 Section 15.10.
74746 * Terminal constructions (such as quantifiers) are parsed directly here.
74747 *
74748 * 0xffffffffU is used as a marker for "infinity" in quantifiers. Further,
74749 * DUK__MAX_RE_QUANT_DIGITS limits the maximum number of digits that
74750 * will be accepted for a quantifier.
74751 */
74752
74753DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token *out_token) {
74754 duk_small_int_t advtok = 0; /* init is unnecessary but suppresses "may be used uninitialized" warnings */
74755 duk_codepoint_t x, y;
74756
74757 if (++lex_ctx->token_count >= lex_ctx->token_limit) {
11fdf7f2 74758 DUK_ERROR_RANGE(lex_ctx->thr, "token limit");
7c673cae
FG
74759 return; /* unreachable */
74760 }
74761
74762 DUK_MEMZERO(out_token, sizeof(*out_token));
74763
74764 x = DUK__L0();
74765 y = DUK__L1();
74766
74767 DUK_DDD(DUK_DDDPRINT("parsing regexp token, L0=%ld, L1=%ld", (long) x, (long) y));
74768
74769 switch (x) {
74770 case '|': {
74771 advtok = DUK__ADVTOK(1, DUK_RETOK_DISJUNCTION);
74772 break;
74773 }
74774 case '^': {
74775 advtok = DUK__ADVTOK(1, DUK_RETOK_ASSERT_START);
74776 break;
74777 }
74778 case '$': {
74779 advtok = DUK__ADVTOK(1, DUK_RETOK_ASSERT_END);
74780 break;
74781 }
74782 case '?': {
74783 out_token->qmin = 0;
74784 out_token->qmax = 1;
74785 if (y == '?') {
74786 advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER);
74787 out_token->greedy = 0;
74788 } else {
74789 advtok = DUK__ADVTOK(1, DUK_RETOK_QUANTIFIER);
74790 out_token->greedy = 1;
74791 }
74792 break;
74793 }
74794 case '*': {
74795 out_token->qmin = 0;
74796 out_token->qmax = DUK_RE_QUANTIFIER_INFINITE;
74797 if (y == '?') {
74798 advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER);
74799 out_token->greedy = 0;
74800 } else {
74801 advtok = DUK__ADVTOK(1, DUK_RETOK_QUANTIFIER);
74802 out_token->greedy = 1;
74803 }
74804 break;
74805 }
74806 case '+': {
74807 out_token->qmin = 1;
74808 out_token->qmax = DUK_RE_QUANTIFIER_INFINITE;
74809 if (y == '?') {
74810 advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER);
74811 out_token->greedy = 0;
74812 } else {
74813 advtok = DUK__ADVTOK(1, DUK_RETOK_QUANTIFIER);
74814 out_token->greedy = 1;
74815 }
74816 break;
74817 }
74818 case '{': {
74819 /* Production allows 'DecimalDigits', including leading zeroes */
74820 duk_uint_fast32_t val1 = 0;
74821 duk_uint_fast32_t val2 = DUK_RE_QUANTIFIER_INFINITE;
74822 duk_small_int_t digits = 0;
11fdf7f2
TL
74823#if defined(DUK_USE_ES6_REGEXP_BRACES)
74824 duk_lexer_point lex_pt;
74825#endif
74826
74827#if defined(DUK_USE_ES6_REGEXP_BRACES)
74828 /* Store lexer position, restoring if quantifier is invalid. */
74829 DUK_LEXER_GETPOINT(lex_ctx, &lex_pt);
74830#endif
74831
7c673cae
FG
74832 for (;;) {
74833 DUK__ADVANCECHARS(lex_ctx, 1); /* eat '{' on entry */
74834 x = DUK__L0();
74835 if (DUK__ISDIGIT(x)) {
7c673cae
FG
74836 digits++;
74837 val1 = val1 * 10 + (duk_uint_fast32_t) duk__hexval(lex_ctx, x);
74838 } else if (x == ',') {
11fdf7f2
TL
74839 if (digits > DUK__MAX_RE_QUANT_DIGITS) {
74840 goto invalid_quantifier;
74841 }
7c673cae 74842 if (val2 != DUK_RE_QUANTIFIER_INFINITE) {
11fdf7f2 74843 goto invalid_quantifier;
7c673cae
FG
74844 }
74845 if (DUK__L1() == '}') {
74846 /* form: { DecimalDigits , }, val1 = min count */
74847 if (digits == 0) {
11fdf7f2 74848 goto invalid_quantifier;
7c673cae
FG
74849 }
74850 out_token->qmin = val1;
74851 out_token->qmax = DUK_RE_QUANTIFIER_INFINITE;
74852 DUK__ADVANCECHARS(lex_ctx, 2);
74853 break;
74854 }
74855 val2 = val1;
74856 val1 = 0;
74857 digits = 0; /* not strictly necessary because of lookahead '}' above */
74858 } else if (x == '}') {
11fdf7f2
TL
74859 if (digits > DUK__MAX_RE_QUANT_DIGITS) {
74860 goto invalid_quantifier;
74861 }
7c673cae 74862 if (digits == 0) {
11fdf7f2 74863 goto invalid_quantifier;
7c673cae
FG
74864 }
74865 if (val2 != DUK_RE_QUANTIFIER_INFINITE) {
74866 /* val2 = min count, val1 = max count */
74867 out_token->qmin = val2;
74868 out_token->qmax = val1;
74869 } else {
74870 /* val1 = count */
74871 out_token->qmin = val1;
74872 out_token->qmax = val1;
74873 }
74874 DUK__ADVANCECHARS(lex_ctx, 1);
74875 break;
74876 } else {
11fdf7f2 74877 goto invalid_quantifier;
7c673cae
FG
74878 }
74879 }
74880 if (DUK__L0() == '?') {
74881 out_token->greedy = 0;
74882 DUK__ADVANCECHARS(lex_ctx, 1);
74883 } else {
74884 out_token->greedy = 1;
74885 }
74886 advtok = DUK__ADVTOK(0, DUK_RETOK_QUANTIFIER);
74887 break;
11fdf7f2
TL
74888 invalid_quantifier:
74889#if defined(DUK_USE_ES6_REGEXP_BRACES)
74890 /* Failed to match the quantifier, restore lexer and parse
74891 * opening brace as a literal.
74892 */
74893 DUK_LEXER_SETPOINT(lex_ctx, &lex_pt);
74894 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_CHAR);
74895 out_token->num = '{';
74896#else
74897 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp quantifier");
74898#endif
74899 break;
7c673cae
FG
74900 }
74901 case '.': {
74902 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_PERIOD);
74903 break;
74904 }
74905 case '\\': {
74906 /* The E5.1 specification does not seem to allow IdentifierPart characters
74907 * to be used as identity escapes. Unfortunately this includes '$', which
74908 * cannot be escaped as '\$'; it needs to be escaped e.g. as '\u0024'.
74909 * Many other implementations (including V8 and Rhino, for instance) do
74910 * accept '\$' as a valid identity escape, which is quite pragmatic.
74911 * See: test-regexp-identity-escape-dollar.js.
74912 */
74913
74914 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_CHAR); /* default: char escape (two chars) */
74915 if (y == 'b') {
74916 advtok = DUK__ADVTOK(2, DUK_RETOK_ASSERT_WORD_BOUNDARY);
74917 } else if (y == 'B') {
74918 advtok = DUK__ADVTOK(2, DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY);
74919 } else if (y == 'f') {
74920 out_token->num = 0x000c;
74921 } else if (y == 'n') {
74922 out_token->num = 0x000a;
74923 } else if (y == 't') {
74924 out_token->num = 0x0009;
74925 } else if (y == 'r') {
74926 out_token->num = 0x000d;
74927 } else if (y == 'v') {
74928 out_token->num = 0x000b;
74929 } else if (y == 'c') {
74930 x = DUK__L2();
74931 if ((x >= 'a' && x <= 'z') ||
74932 (x >= 'A' && x <= 'Z')) {
74933 out_token->num = (x % 32);
74934 advtok = DUK__ADVTOK(3, DUK_RETOK_ATOM_CHAR);
74935 } else {
11fdf7f2 74936 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp escape");
7c673cae
FG
74937 }
74938 } else if (y == 'x') {
74939 out_token->num = duk__decode_hexesc_from_window(lex_ctx, 2);
74940 advtok = DUK__ADVTOK(4, DUK_RETOK_ATOM_CHAR);
74941 } else if (y == 'u') {
74942 out_token->num = duk__decode_uniesc_from_window(lex_ctx, 2);
74943 advtok = DUK__ADVTOK(6, DUK_RETOK_ATOM_CHAR);
74944 } else if (y == 'd') {
74945 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_DIGIT);
74946 } else if (y == 'D') {
74947 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_DIGIT);
74948 } else if (y == 's') {
74949 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_WHITE);
74950 } else if (y == 'S') {
74951 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_WHITE);
74952 } else if (y == 'w') {
74953 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_WORD_CHAR);
74954 } else if (y == 'W') {
74955 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_WORD_CHAR);
74956 } else if (DUK__ISDIGIT(y)) {
74957 /* E5 Section 15.10.2.11 */
74958 if (y == '0') {
74959 if (DUK__ISDIGIT(DUK__L2())) {
11fdf7f2 74960 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp escape");
7c673cae
FG
74961 }
74962 out_token->num = 0x0000;
74963 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_CHAR);
74964 } else {
74965 /* XXX: shared parsing? */
74966 duk_uint_fast32_t val = 0;
74967 duk_small_int_t i;
74968 for (i = 0; ; i++) {
74969 if (i >= DUK__MAX_RE_DECESC_DIGITS) {
11fdf7f2 74970 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp escape");
7c673cae
FG
74971 }
74972 DUK__ADVANCECHARS(lex_ctx, 1); /* eat backslash on entry */
74973 x = DUK__L0();
74974 if (!DUK__ISDIGIT(x)) {
74975 break;
74976 }
74977 val = val * 10 + (duk_uint_fast32_t) duk__hexval(lex_ctx, x);
74978 }
74979 /* DUK__L0() cannot be a digit, because the loop doesn't terminate if it is */
74980 advtok = DUK__ADVTOK(0, DUK_RETOK_ATOM_BACKREFERENCE);
74981 out_token->num = val;
74982 }
74983 } else if ((y >= 0 && !duk_unicode_is_identifier_part(y)) ||
74984#if defined(DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE)
74985 y == '$' ||
74986#endif
74987 y == DUK_UNICODE_CP_ZWNJ ||
74988 y == DUK_UNICODE_CP_ZWJ) {
74989 /* IdentityEscape, with dollar added as a valid additional
74990 * non-standard escape (see test-regexp-identity-escape-dollar.js).
74991 * Careful not to match end-of-buffer (<0) here.
74992 */
74993 out_token->num = y;
74994 } else {
11fdf7f2 74995 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp escape");
7c673cae
FG
74996 }
74997 break;
74998 }
74999 case '(': {
75000 /* XXX: naming is inconsistent: ATOM_END_GROUP ends an ASSERT_START_LOOKAHEAD */
75001
75002 if (y == '?') {
75003 if (DUK__L2() == '=') {
75004 /* (?= */
75005 advtok = DUK__ADVTOK(3, DUK_RETOK_ASSERT_START_POS_LOOKAHEAD);
75006 } else if (DUK__L2() == '!') {
75007 /* (?! */
75008 advtok = DUK__ADVTOK(3, DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD);
75009 } else if (DUK__L2() == ':') {
75010 /* (?: */
75011 advtok = DUK__ADVTOK(3, DUK_RETOK_ATOM_START_NONCAPTURE_GROUP);
11fdf7f2
TL
75012 } else {
75013 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp group");
75014 return;
7c673cae
FG
75015 }
75016 } else {
75017 /* ( */
75018 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_START_CAPTURE_GROUP);
75019 }
75020 break;
75021 }
75022 case ')': {
75023 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_END_GROUP);
75024 break;
75025 }
75026 case '[': {
75027 /*
75028 * To avoid creating a heavy intermediate value for the list of ranges,
75029 * only the start token ('[' or '[^') is parsed here. The regexp
75030 * compiler parses the ranges itself.
75031 */
75032 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_START_CHARCLASS);
75033 if (y == '^') {
75034 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_START_CHARCLASS_INVERTED);
75035 }
75036 break;
75037 }
11fdf7f2
TL
75038#if !defined(DUK_USE_ES6_REGEXP_BRACES)
75039 case '}':
75040#endif
75041 case ']': {
7c673cae
FG
75042 /* Although these could be parsed as PatternCharacters unambiguously (here),
75043 * E5 Section 15.10.1 grammar explicitly forbids these as PatternCharacters.
75044 */
11fdf7f2 75045 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp character");
7c673cae
FG
75046 break;
75047 }
75048 case -1: {
75049 /* EOF */
75050 advtok = DUK__ADVTOK(0, DUK_TOK_EOF);
75051 break;
75052 }
75053 default: {
75054 /* PatternCharacter, all excluded characters are matched by cases above */
75055 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_CHAR);
75056 out_token->num = x;
75057 break;
75058 }
75059 }
75060
75061 /*
75062 * Shared exit path
75063 */
75064
75065 DUK__ADVANCEBYTES(lex_ctx, advtok >> 8);
75066 out_token->t = advtok & 0xff;
75067}
75068
75069/*
75070 * Special parser for character classes; calls callback for every
75071 * range parsed and returns the number of ranges present.
75072 */
75073
75074/* XXX: this duplicates functionality in duk_regexp.c where a similar loop is
75075 * required anyway. We could use that BUT we need to update the regexp compiler
75076 * 'nranges' too. Work this out a bit more cleanly to save space.
75077 */
75078
75079/* XXX: the handling of character range detection is a bit convoluted.
75080 * Try to simplify and make smaller.
75081 */
75082
75083/* XXX: logic for handling character ranges is now incorrect, it will accept
75084 * e.g. [\d-z] whereas it should croak from it? SMJS accepts this too, though.
75085 *
75086 * Needs a read through and a lot of additional tests.
75087 */
75088
75089DUK_LOCAL
75090void duk__emit_u16_direct_ranges(duk_lexer_ctx *lex_ctx,
75091 duk_re_range_callback gen_range,
75092 void *userdata,
11fdf7f2 75093 const duk_uint16_t *ranges,
7c673cae 75094 duk_small_int_t num) {
11fdf7f2 75095 const duk_uint16_t *ranges_end;
7c673cae
FG
75096
75097 DUK_UNREF(lex_ctx);
75098
75099 ranges_end = ranges + num;
75100 while (ranges < ranges_end) {
75101 /* mark range 'direct', bypass canonicalization (see Wiki) */
75102 gen_range(userdata, (duk_codepoint_t) ranges[0], (duk_codepoint_t) ranges[1], 1);
75103 ranges += 2;
75104 }
75105}
75106
75107DUK_INTERNAL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range_callback gen_range, void *userdata) {
75108 duk_codepoint_t start = -1;
75109 duk_codepoint_t ch;
75110 duk_codepoint_t x;
75111 duk_bool_t dash = 0;
75112
75113 DUK_DD(DUK_DDPRINT("parsing regexp ranges"));
75114
75115 for (;;) {
75116 x = DUK__L0();
75117 DUK__ADVANCECHARS(lex_ctx, 1);
75118
75119 ch = -1; /* not strictly necessary, but avoids "uninitialized variable" warnings */
75120 DUK_UNREF(ch);
75121
75122 if (x < 0) {
11fdf7f2 75123 DUK_ERROR_SYNTAX(lex_ctx->thr, "eof in character class");
7c673cae 75124 } else if (x == ']') {
7c673cae
FG
75125 if (start >= 0) {
75126 gen_range(userdata, start, start, 0);
75127 }
75128 break;
75129 } else if (x == '-') {
75130 if (start >= 0 && !dash && DUK__L0() != ']') {
75131 /* '-' as a range indicator */
75132 dash = 1;
75133 continue;
75134 } else {
75135 /* '-' verbatim */
75136 ch = x;
75137 }
75138 } else if (x == '\\') {
75139 /*
75140 * The escapes are same as outside a character class, except that \b has a
75141 * different meaning, and \B and backreferences are prohibited (see E5
75142 * Section 15.10.2.19). However, it's difficult to share code because we
75143 * handle e.g. "\n" very differently: here we generate a single character
75144 * range for it.
75145 */
75146
75147 x = DUK__L0();
75148 DUK__ADVANCECHARS(lex_ctx, 1);
75149
75150 if (x == 'b') {
75151 /* Note: '\b' in char class is different than outside (assertion),
75152 * '\B' is not allowed and is caught by the duk_unicode_is_identifier_part()
75153 * check below.
75154 */
75155 ch = 0x0008;
75156 } else if (x == 'f') {
75157 ch = 0x000c;
75158 } else if (x == 'n') {
75159 ch = 0x000a;
75160 } else if (x == 't') {
75161 ch = 0x0009;
75162 } else if (x == 'r') {
75163 ch = 0x000d;
75164 } else if (x == 'v') {
75165 ch = 0x000b;
75166 } else if (x == 'c') {
75167 x = DUK__L0();
75168 DUK__ADVANCECHARS(lex_ctx, 1);
75169 if ((x >= 'a' && x <= 'z') ||
75170 (x >= 'A' && x <= 'Z')) {
75171 ch = (x % 32);
75172 } else {
11fdf7f2 75173 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp escape");
7c673cae
FG
75174 return; /* never reached, but avoids warnings of
75175 * potentially unused variables.
75176 */
75177 }
75178 } else if (x == 'x') {
75179 ch = duk__decode_hexesc_from_window(lex_ctx, 0);
75180 DUK__ADVANCECHARS(lex_ctx, 2);
75181 } else if (x == 'u') {
75182 ch = duk__decode_uniesc_from_window(lex_ctx, 0);
75183 DUK__ADVANCECHARS(lex_ctx, 4);
75184 } else if (x == 'd') {
75185 duk__emit_u16_direct_ranges(lex_ctx,
75186 gen_range,
75187 userdata,
75188 duk_unicode_re_ranges_digit,
75189 sizeof(duk_unicode_re_ranges_digit) / sizeof(duk_uint16_t));
75190 ch = -1;
75191 } else if (x == 'D') {
75192 duk__emit_u16_direct_ranges(lex_ctx,
75193 gen_range,
75194 userdata,
75195 duk_unicode_re_ranges_not_digit,
75196 sizeof(duk_unicode_re_ranges_not_digit) / sizeof(duk_uint16_t));
75197 ch = -1;
75198 } else if (x == 's') {
75199 duk__emit_u16_direct_ranges(lex_ctx,
75200 gen_range,
75201 userdata,
75202 duk_unicode_re_ranges_white,
75203 sizeof(duk_unicode_re_ranges_white) / sizeof(duk_uint16_t));
75204 ch = -1;
75205 } else if (x == 'S') {
75206 duk__emit_u16_direct_ranges(lex_ctx,
75207 gen_range,
75208 userdata,
75209 duk_unicode_re_ranges_not_white,
75210 sizeof(duk_unicode_re_ranges_not_white) / sizeof(duk_uint16_t));
75211 ch = -1;
75212 } else if (x == 'w') {
75213 duk__emit_u16_direct_ranges(lex_ctx,
75214 gen_range,
75215 userdata,
75216 duk_unicode_re_ranges_wordchar,
75217 sizeof(duk_unicode_re_ranges_wordchar) / sizeof(duk_uint16_t));
75218 ch = -1;
75219 } else if (x == 'W') {
75220 duk__emit_u16_direct_ranges(lex_ctx,
75221 gen_range,
75222 userdata,
75223 duk_unicode_re_ranges_not_wordchar,
75224 sizeof(duk_unicode_re_ranges_not_wordchar) / sizeof(duk_uint16_t));
75225 ch = -1;
75226 } else if (DUK__ISDIGIT(x)) {
75227 /* DecimalEscape, only \0 is allowed, no leading zeroes are allowed */
75228 if (x == '0' && !DUK__ISDIGIT(DUK__L0())) {
75229 ch = 0x0000;
75230 } else {
11fdf7f2 75231 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp escape");
7c673cae
FG
75232 }
75233 } else if (!duk_unicode_is_identifier_part(x)
75234#if defined(DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE)
75235 || x == '$'
75236#endif
75237 ) {
75238 /* IdentityEscape */
75239 ch = x;
75240 } else {
11fdf7f2 75241 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp escape");
7c673cae
FG
75242 }
75243 } else {
75244 /* character represents itself */
75245 ch = x;
75246 }
75247
75248 /* ch is a literal character here or -1 if parsed entity was
75249 * an escape such as "\s".
75250 */
75251
75252 if (ch < 0) {
75253 /* multi-character sets not allowed as part of ranges, see
75254 * E5 Section 15.10.2.15, abstract operation CharacterRange.
75255 */
75256 if (start >= 0) {
75257 if (dash) {
11fdf7f2 75258 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid range");
7c673cae
FG
75259 } else {
75260 gen_range(userdata, start, start, 0);
75261 start = -1;
75262 /* dash is already 0 */
75263 }
75264 }
75265 } else {
75266 if (start >= 0) {
75267 if (dash) {
75268 if (start > ch) {
11fdf7f2 75269 DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid range");
7c673cae
FG
75270 }
75271 gen_range(userdata, start, ch, 0);
75272 start = -1;
75273 dash = 0;
75274 } else {
75275 gen_range(userdata, start, start, 0);
75276 start = ch;
75277 /* dash is already 0 */
75278 }
75279 } else {
75280 start = ch;
75281 }
75282 }
75283 }
75284
75285 return;
75286}
75287
75288#endif /* DUK_USE_REGEXP_SUPPORT */
7c673cae
FG
75289/*
75290 * Number-to-string and string-to-number conversions.
75291 *
75292 * Slow path number-to-string and string-to-number conversion is based on
75293 * a Dragon4 variant, with fast paths for small integers. Big integer
75294 * arithmetic is needed for guaranteeing that the conversion is correct
75295 * and uses a minimum number of digits. The big number arithmetic has a
75296 * fixed maximum size and does not require dynamic allocations.
75297 *
75298 * See: doc/number-conversion.rst.
75299 */
75300
75301/* include removed: duk_internal.h */
75302
75303#define DUK__IEEE_DOUBLE_EXP_BIAS 1023
75304#define DUK__IEEE_DOUBLE_EXP_MIN (-1022) /* biased exp == 0 -> denormal, exp -1022 */
75305
75306#define DUK__DIGITCHAR(x) duk_lc_digits[(x)]
75307
75308/*
75309 * Tables generated with src/gennumdigits.py.
75310 *
75311 * duk__str2num_digits_for_radix indicates, for each radix, how many input
75312 * digits should be considered significant for string-to-number conversion.
75313 * The input is also padded to this many digits to give the Dragon4
75314 * conversion enough (apparent) precision to work with.
75315 *
75316 * duk__str2num_exp_limits indicates, for each radix, the radix-specific
75317 * minimum/maximum exponent values (for a Dragon4 integer mantissa)
75318 * below and above which the number is guaranteed to underflow to zero
75319 * or overflow to Infinity. This allows parsing to keep bigint values
75320 * bounded.
75321 */
75322
75323DUK_LOCAL const duk_uint8_t duk__str2num_digits_for_radix[] = {
75324 69, 44, 35, 30, 27, 25, 23, 22, 20, 20, /* 2 to 11 */
75325 20, 19, 19, 18, 18, 17, 17, 17, 16, 16, /* 12 to 21 */
75326 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, /* 22 to 31 */
75327 14, 14, 14, 14, 14 /* 31 to 36 */
75328};
75329
75330typedef struct {
75331 duk_int16_t upper;
75332 duk_int16_t lower;
75333} duk__exp_limits;
75334
75335DUK_LOCAL const duk__exp_limits duk__str2num_exp_limits[] = {
75336 { 957, -1147 }, { 605, -725 }, { 479, -575 }, { 414, -496 },
75337 { 372, -446 }, { 342, -411 }, { 321, -384 }, { 304, -364 },
75338 { 291, -346 }, { 279, -334 }, { 268, -323 }, { 260, -312 },
75339 { 252, -304 }, { 247, -296 }, { 240, -289 }, { 236, -283 },
75340 { 231, -278 }, { 227, -273 }, { 223, -267 }, { 220, -263 },
75341 { 216, -260 }, { 213, -256 }, { 210, -253 }, { 208, -249 },
75342 { 205, -246 }, { 203, -244 }, { 201, -241 }, { 198, -239 },
75343 { 196, -237 }, { 195, -234 }, { 193, -232 }, { 191, -230 },
75344 { 190, -228 }, { 188, -226 }, { 187, -225 },
75345};
75346
75347/*
75348 * Limited functionality bigint implementation.
75349 *
75350 * Restricted to non-negative numbers with less than 32 * DUK__BI_MAX_PARTS bits,
75351 * with the caller responsible for ensuring this is never exceeded. No memory
75352 * allocation (except stack) is needed for bigint computation. Operations
75353 * have been tailored for number conversion needs.
75354 *
75355 * Argument order is "assignment order", i.e. target first, then arguments:
75356 * x <- y * z --> duk__bi_mul(x, y, z);
75357 */
75358
75359/* This upper value has been experimentally determined; debug build will check
75360 * bigint size with assertions.
75361 */
75362#define DUK__BI_MAX_PARTS 37 /* 37x32 = 1184 bits */
75363
75364#ifdef DUK_USE_DDDPRINT
75365#define DUK__BI_PRINT(name,x) duk__bi_print((name),(x))
75366#else
75367#define DUK__BI_PRINT(name,x)
75368#endif
75369
75370/* Current size is about 152 bytes. */
75371typedef struct {
75372 duk_small_int_t n;
75373 duk_uint32_t v[DUK__BI_MAX_PARTS]; /* low to high */
75374} duk__bigint;
75375
75376#ifdef DUK_USE_DDDPRINT
75377DUK_LOCAL void duk__bi_print(const char *name, duk__bigint *x) {
75378 /* Overestimate required size; debug code so not critical to be tight. */
75379 char buf[DUK__BI_MAX_PARTS * 9 + 64];
75380 char *p = buf;
75381 duk_small_int_t i;
75382
75383 /* No NUL term checks in this debug code. */
75384 p += DUK_SPRINTF(p, "%p n=%ld", (void *) x, (long) x->n);
75385 if (x->n == 0) {
75386 p += DUK_SPRINTF(p, " 0");
75387 }
75388 for (i = x->n - 1; i >= 0; i--) {
75389 p += DUK_SPRINTF(p, " %08lx", (unsigned long) x->v[i]);
75390 }
75391
75392 DUK_DDD(DUK_DDDPRINT("%s: %s", (const char *) name, (const char *) buf));
75393}
75394#endif
75395
75396#ifdef DUK_USE_ASSERTIONS
75397DUK_LOCAL duk_small_int_t duk__bi_is_valid(duk__bigint *x) {
75398 return (duk_small_int_t)
75399 ( ((x->n >= 0) && (x->n <= DUK__BI_MAX_PARTS)) /* is valid size */ &&
75400 ((x->n == 0) || (x->v[x->n - 1] != 0)) /* is normalized */ );
75401}
75402#endif
75403
75404DUK_LOCAL void duk__bi_normalize(duk__bigint *x) {
75405 duk_small_int_t i;
75406
75407 for (i = x->n - 1; i >= 0; i--) {
75408 if (x->v[i] != 0) {
75409 break;
75410 }
75411 }
75412
75413 /* Note: if 'x' is zero, x->n becomes 0 here */
75414 x->n = i + 1;
75415 DUK_ASSERT(duk__bi_is_valid(x));
75416}
75417
75418/* x <- y */
75419DUK_LOCAL void duk__bi_copy(duk__bigint *x, duk__bigint *y) {
75420 duk_small_int_t n;
75421
75422 n = y->n;
75423 x->n = n;
75424 if (n == 0) {
75425 return;
75426 }
11fdf7f2 75427 DUK_MEMCPY((void *) x->v, (const void *) y->v, (size_t) (sizeof(duk_uint32_t) * n));
7c673cae
FG
75428}
75429
75430DUK_LOCAL void duk__bi_set_small(duk__bigint *x, duk_uint32_t v) {
75431 if (v == 0U) {
75432 x->n = 0;
75433 } else {
75434 x->n = 1;
75435 x->v[0] = v;
75436 }
75437 DUK_ASSERT(duk__bi_is_valid(x));
75438}
75439
75440/* Return value: <0 <=> x < y
75441 * 0 <=> x == y
75442 * >0 <=> x > y
75443 */
75444DUK_LOCAL int duk__bi_compare(duk__bigint *x, duk__bigint *y) {
75445 duk_small_int_t i, nx, ny;
75446 duk_uint32_t tx, ty;
75447
75448 DUK_ASSERT(duk__bi_is_valid(x));
75449 DUK_ASSERT(duk__bi_is_valid(y));
75450
75451 nx = x->n;
75452 ny = y->n;
75453 if (nx > ny) {
75454 goto ret_gt;
75455 }
75456 if (nx < ny) {
75457 goto ret_lt;
75458 }
75459 for (i = nx - 1; i >= 0; i--) {
75460 tx = x->v[i];
75461 ty = y->v[i];
75462
75463 if (tx > ty) {
75464 goto ret_gt;
75465 }
75466 if (tx < ty) {
75467 goto ret_lt;
75468 }
75469 }
75470
75471 return 0;
75472
75473 ret_gt:
75474 return 1;
75475
75476 ret_lt:
75477 return -1;
75478}
75479
75480/* x <- y + z */
75481#ifdef DUK_USE_64BIT_OPS
75482DUK_LOCAL void duk__bi_add(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
75483 duk_uint64_t tmp;
75484 duk_small_int_t i, ny, nz;
75485
75486 DUK_ASSERT(duk__bi_is_valid(y));
75487 DUK_ASSERT(duk__bi_is_valid(z));
75488
75489 if (z->n > y->n) {
75490 duk__bigint *t;
75491 t = y; y = z; z = t;
75492 }
75493 DUK_ASSERT(y->n >= z->n);
75494
75495 ny = y->n; nz = z->n;
75496 tmp = 0U;
75497 for (i = 0; i < ny; i++) {
75498 DUK_ASSERT(i < DUK__BI_MAX_PARTS);
75499 tmp += y->v[i];
75500 if (i < nz) {
75501 tmp += z->v[i];
75502 }
75503 x->v[i] = (duk_uint32_t) (tmp & 0xffffffffUL);
75504 tmp = tmp >> 32;
75505 }
75506 if (tmp != 0U) {
75507 DUK_ASSERT(i < DUK__BI_MAX_PARTS);
75508 x->v[i++] = (duk_uint32_t) tmp;
75509 }
75510 x->n = i;
75511 DUK_ASSERT(x->n <= DUK__BI_MAX_PARTS);
75512
75513 /* no need to normalize */
75514 DUK_ASSERT(duk__bi_is_valid(x));
75515}
75516#else /* DUK_USE_64BIT_OPS */
75517DUK_LOCAL void duk__bi_add(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
75518 duk_uint32_t carry, tmp1, tmp2;
75519 duk_small_int_t i, ny, nz;
75520
75521 DUK_ASSERT(duk__bi_is_valid(y));
75522 DUK_ASSERT(duk__bi_is_valid(z));
75523
75524 if (z->n > y->n) {
75525 duk__bigint *t;
75526 t = y; y = z; z = t;
75527 }
75528 DUK_ASSERT(y->n >= z->n);
75529
75530 ny = y->n; nz = z->n;
75531 carry = 0U;
75532 for (i = 0; i < ny; i++) {
75533 /* Carry is detected based on wrapping which relies on exact 32-bit
75534 * types.
75535 */
75536 DUK_ASSERT(i < DUK__BI_MAX_PARTS);
75537 tmp1 = y->v[i];
75538 tmp2 = tmp1;
75539 if (i < nz) {
75540 tmp2 += z->v[i];
75541 }
75542
75543 /* Careful with carry condition:
75544 * - If carry not added: 0x12345678 + 0 + 0xffffffff = 0x12345677 (< 0x12345678)
75545 * - If carry added: 0x12345678 + 1 + 0xffffffff = 0x12345678 (== 0x12345678)
75546 */
75547 if (carry) {
75548 tmp2++;
75549 carry = (tmp2 <= tmp1 ? 1U : 0U);
75550 } else {
75551 carry = (tmp2 < tmp1 ? 1U : 0U);
75552 }
75553
75554 x->v[i] = tmp2;
75555 }
75556 if (carry) {
75557 DUK_ASSERT(i < DUK__BI_MAX_PARTS);
75558 DUK_ASSERT(carry == 1U);
75559 x->v[i++] = carry;
75560 }
75561 x->n = i;
75562 DUK_ASSERT(x->n <= DUK__BI_MAX_PARTS);
75563
75564 /* no need to normalize */
75565 DUK_ASSERT(duk__bi_is_valid(x));
75566}
75567#endif /* DUK_USE_64BIT_OPS */
75568
75569/* x <- y + z */
75570DUK_LOCAL void duk__bi_add_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z) {
75571 duk__bigint tmp;
75572
75573 DUK_ASSERT(duk__bi_is_valid(y));
75574
75575 /* XXX: this could be optimized; there is only one call site now though */
75576 duk__bi_set_small(&tmp, z);
75577 duk__bi_add(x, y, &tmp);
75578
75579 DUK_ASSERT(duk__bi_is_valid(x));
75580}
75581
75582#if 0 /* unused */
75583/* x <- x + y, use t as temp */
75584DUK_LOCAL void duk__bi_add_copy(duk__bigint *x, duk__bigint *y, duk__bigint *t) {
75585 duk__bi_add(t, x, y);
75586 duk__bi_copy(x, t);
75587}
75588#endif
75589
75590/* x <- y - z, require x >= y => z >= 0, i.e. y >= z */
75591#ifdef DUK_USE_64BIT_OPS
75592DUK_LOCAL void duk__bi_sub(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
75593 duk_small_int_t i, ny, nz;
75594 duk_uint32_t ty, tz;
75595 duk_int64_t tmp;
75596
75597 DUK_ASSERT(duk__bi_is_valid(y));
75598 DUK_ASSERT(duk__bi_is_valid(z));
75599 DUK_ASSERT(duk__bi_compare(y, z) >= 0);
75600 DUK_ASSERT(y->n >= z->n);
75601
75602 ny = y->n; nz = z->n;
75603 tmp = 0;
75604 for (i = 0; i < ny; i++) {
75605 ty = y->v[i];
75606 if (i < nz) {
75607 tz = z->v[i];
75608 } else {
75609 tz = 0;
75610 }
75611 tmp = (duk_int64_t) ty - (duk_int64_t) tz + tmp;
75612 x->v[i] = (duk_uint32_t) (tmp & 0xffffffffUL);
75613 tmp = tmp >> 32; /* 0 or -1 */
75614 }
75615 DUK_ASSERT(tmp == 0);
75616
75617 x->n = i;
75618 duk__bi_normalize(x); /* need to normalize, may even cancel to 0 */
75619 DUK_ASSERT(duk__bi_is_valid(x));
75620}
75621#else
75622DUK_LOCAL void duk__bi_sub(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
75623 duk_small_int_t i, ny, nz;
75624 duk_uint32_t tmp1, tmp2, borrow;
75625
75626 DUK_ASSERT(duk__bi_is_valid(y));
75627 DUK_ASSERT(duk__bi_is_valid(z));
75628 DUK_ASSERT(duk__bi_compare(y, z) >= 0);
75629 DUK_ASSERT(y->n >= z->n);
75630
75631 ny = y->n; nz = z->n;
75632 borrow = 0U;
75633 for (i = 0; i < ny; i++) {
75634 /* Borrow is detected based on wrapping which relies on exact 32-bit
75635 * types.
75636 */
75637 tmp1 = y->v[i];
75638 tmp2 = tmp1;
75639 if (i < nz) {
75640 tmp2 -= z->v[i];
75641 }
75642
75643 /* Careful with borrow condition:
75644 * - If borrow not subtracted: 0x12345678 - 0 - 0xffffffff = 0x12345679 (> 0x12345678)
75645 * - If borrow subtracted: 0x12345678 - 1 - 0xffffffff = 0x12345678 (== 0x12345678)
75646 */
75647 if (borrow) {
75648 tmp2--;
75649 borrow = (tmp2 >= tmp1 ? 1U : 0U);
75650 } else {
75651 borrow = (tmp2 > tmp1 ? 1U : 0U);
75652 }
75653
75654 x->v[i] = tmp2;
75655 }
75656 DUK_ASSERT(borrow == 0U);
75657
75658 x->n = i;
75659 duk__bi_normalize(x); /* need to normalize, may even cancel to 0 */
75660 DUK_ASSERT(duk__bi_is_valid(x));
75661}
75662#endif
75663
75664#if 0 /* unused */
75665/* x <- y - z */
75666DUK_LOCAL void duk__bi_sub_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z) {
75667 duk__bigint tmp;
75668
75669 DUK_ASSERT(duk__bi_is_valid(y));
75670
75671 /* XXX: this could be optimized */
75672 duk__bi_set_small(&tmp, z);
75673 duk__bi_sub(x, y, &tmp);
75674
75675 DUK_ASSERT(duk__bi_is_valid(x));
75676}
75677#endif
75678
75679/* x <- x - y, use t as temp */
75680DUK_LOCAL void duk__bi_sub_copy(duk__bigint *x, duk__bigint *y, duk__bigint *t) {
75681 duk__bi_sub(t, x, y);
75682 duk__bi_copy(x, t);
75683}
75684
75685/* x <- y * z */
75686DUK_LOCAL void duk__bi_mul(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
75687 duk_small_int_t i, j, nx, nz;
75688
75689 DUK_ASSERT(duk__bi_is_valid(y));
75690 DUK_ASSERT(duk__bi_is_valid(z));
75691
75692 nx = y->n + z->n; /* max possible */
75693 DUK_ASSERT(nx <= DUK__BI_MAX_PARTS);
75694
75695 if (nx == 0) {
75696 /* Both inputs are zero; cases where only one is zero can go
75697 * through main algorithm.
75698 */
75699 x->n = 0;
75700 return;
75701 }
75702
75703 DUK_MEMZERO((void *) x->v, (size_t) (sizeof(duk_uint32_t) * nx));
75704 x->n = nx;
75705
75706 nz = z->n;
75707 for (i = 0; i < y->n; i++) {
75708#ifdef DUK_USE_64BIT_OPS
75709 duk_uint64_t tmp = 0U;
75710 for (j = 0; j < nz; j++) {
75711 tmp += (duk_uint64_t) y->v[i] * (duk_uint64_t) z->v[j] + x->v[i+j];
75712 x->v[i+j] = (duk_uint32_t) (tmp & 0xffffffffUL);
75713 tmp = tmp >> 32;
75714 }
75715 if (tmp > 0) {
75716 DUK_ASSERT(i + j < nx);
75717 DUK_ASSERT(i + j < DUK__BI_MAX_PARTS);
75718 DUK_ASSERT(x->v[i+j] == 0U);
75719 x->v[i+j] = (duk_uint32_t) tmp;
75720 }
75721#else
75722 /*
75723 * Multiply + add + carry for 32-bit components using only 16x16->32
75724 * multiplies and carry detection based on unsigned overflow.
75725 *
75726 * 1st mult, 32-bit: (A*2^16 + B)
75727 * 2nd mult, 32-bit: (C*2^16 + D)
75728 * 3rd add, 32-bit: E
75729 * 4th add, 32-bit: F
75730 *
75731 * (AC*2^16 + B) * (C*2^16 + D) + E + F
75732 * = AC*2^32 + AD*2^16 + BC*2^16 + BD + E + F
75733 * = AC*2^32 + (AD + BC)*2^16 + (BD + E + F)
75734 * = AC*2^32 + AD*2^16 + BC*2^16 + (BD + E + F)
75735 */
75736 duk_uint32_t a, b, c, d, e, f;
75737 duk_uint32_t r, s, t;
75738
75739 a = y->v[i]; b = a & 0xffffUL; a = a >> 16;
75740
75741 f = 0;
75742 for (j = 0; j < nz; j++) {
75743 c = z->v[j]; d = c & 0xffffUL; c = c >> 16;
75744 e = x->v[i+j];
75745
75746 /* build result as: (r << 32) + s: start with (BD + E + F) */
75747 r = 0;
75748 s = b * d;
75749
75750 /* add E */
75751 t = s + e;
75752 if (t < s) { r++; } /* carry */
75753 s = t;
75754
75755 /* add F */
75756 t = s + f;
75757 if (t < s) { r++; } /* carry */
75758 s = t;
75759
75760 /* add BC*2^16 */
75761 t = b * c;
75762 r += (t >> 16);
75763 t = s + ((t & 0xffffUL) << 16);
75764 if (t < s) { r++; } /* carry */
75765 s = t;
75766
75767 /* add AD*2^16 */
75768 t = a * d;
75769 r += (t >> 16);
75770 t = s + ((t & 0xffffUL) << 16);
75771 if (t < s) { r++; } /* carry */
75772 s = t;
75773
75774 /* add AC*2^32 */
75775 t = a * c;
75776 r += t;
75777
75778 DUK_DDD(DUK_DDDPRINT("ab=%08lx cd=%08lx ef=%08lx -> rs=%08lx %08lx",
75779 (unsigned long) y->v[i], (unsigned long) z->v[j],
75780 (unsigned long) x->v[i+j], (unsigned long) r,
75781 (unsigned long) s));
75782
75783 x->v[i+j] = s;
75784 f = r;
75785 }
75786 if (f > 0U) {
75787 DUK_ASSERT(i + j < nx);
75788 DUK_ASSERT(i + j < DUK__BI_MAX_PARTS);
75789 DUK_ASSERT(x->v[i+j] == 0U);
75790 x->v[i+j] = (duk_uint32_t) f;
75791 }
75792#endif /* DUK_USE_64BIT_OPS */
75793 }
75794
75795 duk__bi_normalize(x);
75796 DUK_ASSERT(duk__bi_is_valid(x));
75797}
75798
75799/* x <- y * z */
75800DUK_LOCAL void duk__bi_mul_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z) {
75801 duk__bigint tmp;
75802
75803 DUK_ASSERT(duk__bi_is_valid(y));
75804
75805 /* XXX: this could be optimized */
75806 duk__bi_set_small(&tmp, z);
75807 duk__bi_mul(x, y, &tmp);
75808
75809 DUK_ASSERT(duk__bi_is_valid(x));
75810}
75811
75812/* x <- x * y, use t as temp */
75813DUK_LOCAL void duk__bi_mul_copy(duk__bigint *x, duk__bigint *y, duk__bigint *t) {
75814 duk__bi_mul(t, x, y);
75815 duk__bi_copy(x, t);
75816}
75817
75818/* x <- x * y, use t as temp */
75819DUK_LOCAL void duk__bi_mul_small_copy(duk__bigint *x, duk_uint32_t y, duk__bigint *t) {
75820 duk__bi_mul_small(t, x, y);
75821 duk__bi_copy(x, t);
75822}
75823
75824DUK_LOCAL int duk__bi_is_even(duk__bigint *x) {
75825 DUK_ASSERT(duk__bi_is_valid(x));
75826 return (x->n == 0) || ((x->v[0] & 0x01) == 0);
75827}
75828
75829DUK_LOCAL int duk__bi_is_zero(duk__bigint *x) {
75830 DUK_ASSERT(duk__bi_is_valid(x));
75831 return (x->n == 0); /* this is the case for normalized numbers */
75832}
75833
75834/* Bigint is 2^52. Used to detect normalized IEEE double mantissa values
75835 * which are at the lowest edge (next floating point value downwards has
75836 * a different exponent). The lowest mantissa has the form:
75837 *
75838 * 1000........000 (52 zeroes; only "hidden bit" is set)
75839 */
75840DUK_LOCAL duk_small_int_t duk__bi_is_2to52(duk__bigint *x) {
75841 DUK_ASSERT(duk__bi_is_valid(x));
75842 return (duk_small_int_t)
75843 (x->n == 2) && (x->v[0] == 0U) && (x->v[1] == (1U << (52-32)));
75844}
75845
75846/* x <- (1<<y) */
75847DUK_LOCAL void duk__bi_twoexp(duk__bigint *x, duk_small_int_t y) {
75848 duk_small_int_t n, r;
75849
75850 n = (y / 32) + 1;
75851 DUK_ASSERT(n > 0);
75852 r = y % 32;
75853 DUK_MEMZERO((void *) x->v, sizeof(duk_uint32_t) * n);
75854 x->n = n;
75855 x->v[n - 1] = (((duk_uint32_t) 1) << r);
75856}
75857
75858/* x <- b^y; use t1 and t2 as temps */
75859DUK_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) {
75860 /* Fast path the binary case */
75861
75862 DUK_ASSERT(x != t1 && x != t2 && t1 != t2); /* distinct bignums, easy mistake to make */
75863 DUK_ASSERT(b >= 0);
75864 DUK_ASSERT(y >= 0);
75865
75866 if (b == 2) {
75867 duk__bi_twoexp(x, y);
75868 return;
75869 }
75870
75871 /* http://en.wikipedia.org/wiki/Exponentiation_by_squaring */
75872
75873 DUK_DDD(DUK_DDDPRINT("exp_small: b=%ld, y=%ld", (long) b, (long) y));
75874
75875 duk__bi_set_small(x, 1);
75876 duk__bi_set_small(t1, b);
75877 for (;;) {
75878 /* Loop structure ensures that we don't compute t1^2 unnecessarily
75879 * on the final round, as that might create a bignum exceeding the
75880 * current DUK__BI_MAX_PARTS limit.
75881 */
75882 if (y & 0x01) {
75883 duk__bi_mul_copy(x, t1, t2);
75884 }
75885 y = y >> 1;
75886 if (y == 0) {
75887 break;
75888 }
75889 duk__bi_mul_copy(t1, t1, t2);
75890 }
75891
75892 DUK__BI_PRINT("exp_small result", x);
75893}
75894
75895/*
75896 * A Dragon4 number-to-string variant, based on:
75897 *
75898 * Guy L. Steele Jr., Jon L. White: "How to Print Floating-Point Numbers
75899 * Accurately"
75900 *
75901 * Robert G. Burger, R. Kent Dybvig: "Printing Floating-Point Numbers
75902 * Quickly and Accurately"
75903 *
75904 * The current algorithm is based on Figure 1 of the Burger-Dybvig paper,
75905 * i.e. the base implementation without logarithm estimation speedups
75906 * (these would increase code footprint considerably). Fixed-format output
75907 * does not follow the suggestions in the paper; instead, we generate an
75908 * extra digit and round-with-carry.
75909 *
75910 * The same algorithm is used for number parsing (with b=10 and B=2)
75911 * by generating one extra digit and doing rounding manually.
75912 *
75913 * See doc/number-conversion.rst for limitations.
75914 */
75915
75916/* Maximum number of digits generated. */
75917#define DUK__MAX_OUTPUT_DIGITS 1040 /* (Number.MAX_VALUE).toString(2).length == 1024, + spare */
75918
75919/* Maximum number of characters in formatted value. */
75920#define DUK__MAX_FORMATTED_LENGTH 1040 /* (-Number.MAX_VALUE).toString(2).length == 1025, + spare */
75921
75922/* Number and (minimum) size of bigints in the nc_ctx structure. */
75923#define DUK__NUMCONV_CTX_NUM_BIGINTS 7
75924#define DUK__NUMCONV_CTX_BIGINTS_SIZE (sizeof(duk__bigint) * DUK__NUMCONV_CTX_NUM_BIGINTS)
75925
75926typedef struct {
75927 /* Currently about 7*152 = 1064 bytes. The space for these
75928 * duk__bigints is used also as a temporary buffer for generating
75929 * the final string. This is a bit awkard; a union would be
75930 * more correct.
75931 */
75932 duk__bigint f, r, s, mp, mm, t1, t2;
75933
75934 duk_small_int_t is_s2n; /* if 1, doing a string-to-number; else doing a number-to-string */
75935 duk_small_int_t is_fixed; /* if 1, doing a fixed format output (not free format) */
75936 duk_small_int_t req_digits; /* requested number of output digits; 0 = free-format */
75937 duk_small_int_t abs_pos; /* digit position is absolute, not relative */
75938 duk_small_int_t e; /* exponent for 'f' */
75939 duk_small_int_t b; /* input radix */
75940 duk_small_int_t B; /* output radix */
75941 duk_small_int_t k; /* see algorithm */
75942 duk_small_int_t low_ok; /* see algorithm */
75943 duk_small_int_t high_ok; /* see algorithm */
75944 duk_small_int_t unequal_gaps; /* m+ != m- (very rarely) */
75945
75946 /* Buffer used for generated digits, values are in the range [0,B-1]. */
75947 duk_uint8_t digits[DUK__MAX_OUTPUT_DIGITS];
75948 duk_small_int_t count; /* digit count */
75949} duk__numconv_stringify_ctx;
75950
75951/* Note: computes with 'idx' in assertions, so caller beware.
75952 * 'idx' is preincremented, i.e. '1' on first call, because it
75953 * is more convenient for the caller.
75954 */
75955#define DUK__DRAGON4_OUTPUT_PREINC(nc_ctx,preinc_idx,x) do { \
75956 DUK_ASSERT((preinc_idx) - 1 >= 0); \
75957 DUK_ASSERT((preinc_idx) - 1 < DUK__MAX_OUTPUT_DIGITS); \
75958 ((nc_ctx)->digits[(preinc_idx) - 1]) = (duk_uint8_t) (x); \
75959 } while (0)
75960
75961DUK_LOCAL duk_size_t duk__dragon4_format_uint32(duk_uint8_t *buf, duk_uint32_t x, duk_small_int_t radix) {
75962 duk_uint8_t *p;
75963 duk_size_t len;
75964 duk_small_int_t dig;
75965 duk_small_int_t t;
75966
75967 DUK_ASSERT(radix >= 2 && radix <= 36);
75968
75969 /* A 32-bit unsigned integer formats to at most 32 digits (the
75970 * worst case happens with radix == 2). Output the digits backwards,
75971 * and use a memmove() to get them in the right place.
75972 */
75973
75974 p = buf + 32;
75975 for (;;) {
75976 t = x / radix;
75977 dig = x - t * radix;
75978 x = t;
75979
75980 DUK_ASSERT(dig >= 0 && dig < 36);
75981 *(--p) = DUK__DIGITCHAR(dig);
75982
75983 if (x == 0) {
75984 break;
75985 }
75986 }
75987 len = (duk_size_t) ((buf + 32) - p);
75988
11fdf7f2 75989 DUK_MEMMOVE((void *) buf, (const void *) p, (size_t) len);
7c673cae
FG
75990
75991 return len;
75992}
75993
75994DUK_LOCAL void duk__dragon4_prepare(duk__numconv_stringify_ctx *nc_ctx) {
75995 duk_small_int_t lowest_mantissa;
75996
75997#if 1
75998 /* Assume IEEE round-to-even, so that shorter encoding can be used
75999 * when round-to-even would produce correct result. By removing
76000 * this check (and having low_ok == high_ok == 0) the results would
76001 * still be accurate but in some cases longer than necessary.
76002 */
76003 if (duk__bi_is_even(&nc_ctx->f)) {
76004 DUK_DDD(DUK_DDDPRINT("f is even"));
76005 nc_ctx->low_ok = 1;
76006 nc_ctx->high_ok = 1;
76007 } else {
76008 DUK_DDD(DUK_DDDPRINT("f is odd"));
76009 nc_ctx->low_ok = 0;
76010 nc_ctx->high_ok = 0;
76011 }
76012#else
76013 /* Note: not honoring round-to-even should work but now generates incorrect
76014 * results. For instance, 1e23 serializes to "a000...", i.e. the first digit
76015 * equals the radix (10). Scaling stops one step too early in this case.
76016 * Don't know why this is the case, but since this code path is unused, it
76017 * doesn't matter.
76018 */
76019 nc_ctx->low_ok = 0;
76020 nc_ctx->high_ok = 0;
76021#endif
76022
76023 /* For string-to-number, pretend we never have the lowest mantissa as there
76024 * is no natural "precision" for inputs. Having lowest_mantissa == 0, we'll
76025 * fall into the base cases for both e >= 0 and e < 0.
76026 */
76027 if (nc_ctx->is_s2n) {
76028 lowest_mantissa = 0;
76029 } else {
76030 lowest_mantissa = duk__bi_is_2to52(&nc_ctx->f);
76031 }
76032
76033 nc_ctx->unequal_gaps = 0;
76034 if (nc_ctx->e >= 0) {
76035 /* exponent non-negative (and thus not minimum exponent) */
76036
76037 if (lowest_mantissa) {
76038 /* (>= e 0) AND (= f (expt b (- p 1)))
76039 *
76040 * be <- (expt b e) == b^e
76041 * be1 <- (* be b) == (expt b (+ e 1)) == b^(e+1)
76042 * r <- (* f be1 2) == 2 * f * b^(e+1) [if b==2 -> f * b^(e+2)]
76043 * s <- (* b 2) [if b==2 -> 4]
76044 * m+ <- be1 == b^(e+1)
76045 * m- <- be == b^e
76046 * k <- 0
76047 * B <- B
76048 * low_ok <- round
76049 * high_ok <- round
76050 */
76051
76052 DUK_DDD(DUK_DDDPRINT("non-negative exponent (not smallest exponent); "
76053 "lowest mantissa value for this exponent -> "
76054 "unequal gaps"));
76055
76056 duk__bi_exp_small(&nc_ctx->mm, nc_ctx->b, nc_ctx->e, &nc_ctx->t1, &nc_ctx->t2); /* mm <- b^e */
76057 duk__bi_mul_small(&nc_ctx->mp, &nc_ctx->mm, nc_ctx->b); /* mp <- b^(e+1) */
76058 duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, 2);
76059 duk__bi_mul(&nc_ctx->r, &nc_ctx->t1, &nc_ctx->mp); /* r <- (2 * f) * b^(e+1) */
76060 duk__bi_set_small(&nc_ctx->s, nc_ctx->b * 2); /* s <- 2 * b */
76061 nc_ctx->unequal_gaps = 1;
76062 } else {
76063 /* (>= e 0) AND (not (= f (expt b (- p 1))))
76064 *
76065 * be <- (expt b e) == b^e
76066 * r <- (* f be 2) == 2 * f * b^e [if b==2 -> f * b^(e+1)]
76067 * s <- 2
76068 * m+ <- be == b^e
76069 * m- <- be == b^e
76070 * k <- 0
76071 * B <- B
76072 * low_ok <- round
76073 * high_ok <- round
76074 */
76075
76076 DUK_DDD(DUK_DDDPRINT("non-negative exponent (not smallest exponent); "
76077 "not lowest mantissa for this exponent -> "
76078 "equal gaps"));
76079
76080 duk__bi_exp_small(&nc_ctx->mm, nc_ctx->b, nc_ctx->e, &nc_ctx->t1, &nc_ctx->t2); /* mm <- b^e */
76081 duk__bi_copy(&nc_ctx->mp, &nc_ctx->mm); /* mp <- b^e */
76082 duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, 2);
76083 duk__bi_mul(&nc_ctx->r, &nc_ctx->t1, &nc_ctx->mp); /* r <- (2 * f) * b^e */
76084 duk__bi_set_small(&nc_ctx->s, 2); /* s <- 2 */
76085 }
76086 } else {
76087 /* When doing string-to-number, lowest_mantissa is always 0 so
76088 * the exponent check, while incorrect, won't matter.
76089 */
76090 if (nc_ctx->e > DUK__IEEE_DOUBLE_EXP_MIN /*not minimum exponent*/ &&
76091 lowest_mantissa /* lowest mantissa for this exponent*/) {
76092 /* r <- (* f b 2) [if b==2 -> (* f 4)]
76093 * s <- (* (expt b (- 1 e)) 2) == b^(1-e) * 2 [if b==2 -> b^(2-e)]
76094 * m+ <- b == 2
76095 * m- <- 1
76096 * k <- 0
76097 * B <- B
76098 * low_ok <- round
76099 * high_ok <- round
76100 */
76101
76102 DUK_DDD(DUK_DDDPRINT("negative exponent; not minimum exponent and "
76103 "lowest mantissa for this exponent -> "
76104 "unequal gaps"));
76105
76106 duk__bi_mul_small(&nc_ctx->r, &nc_ctx->f, nc_ctx->b * 2); /* r <- (2 * b) * f */
76107 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 */
76108 duk__bi_mul_small(&nc_ctx->s, &nc_ctx->t1, 2); /* s <- b^(1-e) * 2 */
76109 duk__bi_set_small(&nc_ctx->mp, 2);
76110 duk__bi_set_small(&nc_ctx->mm, 1);
76111 nc_ctx->unequal_gaps = 1;
76112 } else {
76113 /* r <- (* f 2)
76114 * s <- (* (expt b (- e)) 2) == b^(-e) * 2 [if b==2 -> b^(1-e)]
76115 * m+ <- 1
76116 * m- <- 1
76117 * k <- 0
76118 * B <- B
76119 * low_ok <- round
76120 * high_ok <- round
76121 */
76122
76123 DUK_DDD(DUK_DDDPRINT("negative exponent; minimum exponent or not "
76124 "lowest mantissa for this exponent -> "
76125 "equal gaps"));
76126
76127 duk__bi_mul_small(&nc_ctx->r, &nc_ctx->f, 2); /* r <- 2 * f */
76128 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 */
76129 duk__bi_mul_small(&nc_ctx->s, &nc_ctx->t1, 2); /* s <- b^(-e) * 2 */
76130 duk__bi_set_small(&nc_ctx->mp, 1);
76131 duk__bi_set_small(&nc_ctx->mm, 1);
76132 }
76133 }
76134}
76135
76136DUK_LOCAL void duk__dragon4_scale(duk__numconv_stringify_ctx *nc_ctx) {
76137 duk_small_int_t k = 0;
76138
76139 /* This is essentially the 'scale' algorithm, with recursion removed.
76140 * Note that 'k' is either correct immediately, or will move in one
76141 * direction in the loop. There's no need to do the low/high checks
76142 * on every round (like the Scheme algorithm does).
76143 *
76144 * The scheme algorithm finds 'k' and updates 's' simultaneously,
76145 * while the logical algorithm finds 'k' with 's' having its initial
76146 * value, after which 's' is updated separately (see the Burger-Dybvig
76147 * paper, Section 3.1, steps 2 and 3).
76148 *
76149 * The case where m+ == m- (almost always) is optimized for, because
76150 * it reduces the bigint operations considerably and almost always
76151 * applies. The scale loop only needs to work with m+, so this works.
76152 */
76153
76154 /* XXX: this algorithm could be optimized quite a lot by using e.g.
76155 * a logarithm based estimator for 'k' and performing B^n multiplication
76156 * using a lookup table or using some bit-representation based exp
76157 * algorithm. Currently we just loop, with significant performance
76158 * impact for very large and very small numbers.
76159 */
76160
76161 DUK_DDD(DUK_DDDPRINT("scale: B=%ld, low_ok=%ld, high_ok=%ld",
76162 (long) nc_ctx->B, (long) nc_ctx->low_ok, (long) nc_ctx->high_ok));
76163 DUK__BI_PRINT("r(init)", &nc_ctx->r);
76164 DUK__BI_PRINT("s(init)", &nc_ctx->s);
76165 DUK__BI_PRINT("mp(init)", &nc_ctx->mp);
76166 DUK__BI_PRINT("mm(init)", &nc_ctx->mm);
76167
76168 for (;;) {
76169 DUK_DDD(DUK_DDDPRINT("scale loop (inc k), k=%ld", (long) k));
76170 DUK__BI_PRINT("r", &nc_ctx->r);
76171 DUK__BI_PRINT("s", &nc_ctx->s);
76172 DUK__BI_PRINT("m+", &nc_ctx->mp);
76173 DUK__BI_PRINT("m-", &nc_ctx->mm);
76174
76175 duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp); /* t1 = (+ r m+) */
76176 if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) >= (nc_ctx->high_ok ? 0 : 1)) {
76177 DUK_DDD(DUK_DDDPRINT("k is too low"));
76178 /* r <- r
76179 * s <- (* s B)
76180 * m+ <- m+
76181 * m- <- m-
76182 * k <- (+ k 1)
76183 */
76184
76185 duk__bi_mul_small_copy(&nc_ctx->s, nc_ctx->B, &nc_ctx->t1);
76186 k++;
76187 } else {
76188 break;
76189 }
76190 }
76191
76192 /* k > 0 -> k was too low, and cannot be too high */
76193 if (k > 0) {
76194 goto skip_dec_k;
76195 }
76196
76197 for (;;) {
76198 DUK_DDD(DUK_DDDPRINT("scale loop (dec k), k=%ld", (long) k));
76199 DUK__BI_PRINT("r", &nc_ctx->r);
76200 DUK__BI_PRINT("s", &nc_ctx->s);
76201 DUK__BI_PRINT("m+", &nc_ctx->mp);
76202 DUK__BI_PRINT("m-", &nc_ctx->mm);
76203
76204 duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp); /* t1 = (+ r m+) */
76205 duk__bi_mul_small(&nc_ctx->t2, &nc_ctx->t1, nc_ctx->B); /* t2 = (* (+ r m+) B) */
76206 if (duk__bi_compare(&nc_ctx->t2, &nc_ctx->s) <= (nc_ctx->high_ok ? -1 : 0)) {
76207 DUK_DDD(DUK_DDDPRINT("k is too high"));
76208 /* r <- (* r B)
76209 * s <- s
76210 * m+ <- (* m+ B)
76211 * m- <- (* m- B)
76212 * k <- (- k 1)
76213 */
76214 duk__bi_mul_small_copy(&nc_ctx->r, nc_ctx->B, &nc_ctx->t1);
76215 duk__bi_mul_small_copy(&nc_ctx->mp, nc_ctx->B, &nc_ctx->t1);
76216 if (nc_ctx->unequal_gaps) {
76217 DUK_DDD(DUK_DDDPRINT("m+ != m- -> need to update m- too"));
76218 duk__bi_mul_small_copy(&nc_ctx->mm, nc_ctx->B, &nc_ctx->t1);
76219 }
76220 k--;
76221 } else {
76222 break;
76223 }
76224 }
76225
76226 skip_dec_k:
76227
76228 if (!nc_ctx->unequal_gaps) {
76229 DUK_DDD(DUK_DDDPRINT("equal gaps, copy m- from m+"));
76230 duk__bi_copy(&nc_ctx->mm, &nc_ctx->mp); /* mm <- mp */
76231 }
76232 nc_ctx->k = k;
76233
76234 DUK_DDD(DUK_DDDPRINT("final k: %ld", (long) k));
76235 DUK__BI_PRINT("r(final)", &nc_ctx->r);
76236 DUK__BI_PRINT("s(final)", &nc_ctx->s);
76237 DUK__BI_PRINT("mp(final)", &nc_ctx->mp);
76238 DUK__BI_PRINT("mm(final)", &nc_ctx->mm);
76239}
76240
76241DUK_LOCAL void duk__dragon4_generate(duk__numconv_stringify_ctx *nc_ctx) {
76242 duk_small_int_t tc1, tc2; /* terminating conditions */
76243 duk_small_int_t d; /* current digit */
76244 duk_small_int_t count = 0; /* digit count */
76245
76246 /*
76247 * Digit generation loop.
76248 *
76249 * Different termination conditions:
76250 *
76251 * 1. Free format output. Terminate when shortest accurate
76252 * representation found.
76253 *
76254 * 2. Fixed format output, with specific number of digits.
76255 * Ignore termination conditions, terminate when digits
76256 * generated. Caller requests an extra digit and rounds.
76257 *
76258 * 3. Fixed format output, with a specific absolute cut-off
76259 * position (e.g. 10 digits after decimal point). Note
76260 * that we always generate at least one digit, even if
76261 * the digit is below the cut-off point already.
76262 */
76263
76264 for (;;) {
76265 DUK_DDD(DUK_DDDPRINT("generate loop, count=%ld, k=%ld, B=%ld, low_ok=%ld, high_ok=%ld",
76266 (long) count, (long) nc_ctx->k, (long) nc_ctx->B,
76267 (long) nc_ctx->low_ok, (long) nc_ctx->high_ok));
76268 DUK__BI_PRINT("r", &nc_ctx->r);
76269 DUK__BI_PRINT("s", &nc_ctx->s);
76270 DUK__BI_PRINT("m+", &nc_ctx->mp);
76271 DUK__BI_PRINT("m-", &nc_ctx->mm);
76272
76273 /* (quotient-remainder (* r B) s) using a dummy subtraction loop */
76274 duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->r, nc_ctx->B); /* t1 <- (* r B) */
76275 d = 0;
76276 for (;;) {
76277 if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) < 0) {
76278 break;
76279 }
76280 duk__bi_sub_copy(&nc_ctx->t1, &nc_ctx->s, &nc_ctx->t2); /* t1 <- t1 - s */
76281 d++;
76282 }
76283 duk__bi_copy(&nc_ctx->r, &nc_ctx->t1); /* r <- (remainder (* r B) s) */
76284 /* d <- (quotient (* r B) s) (in range 0...B-1) */
76285 DUK_DDD(DUK_DDDPRINT("-> d(quot)=%ld", (long) d));
76286 DUK__BI_PRINT("r(rem)", &nc_ctx->r);
76287
76288 duk__bi_mul_small_copy(&nc_ctx->mp, nc_ctx->B, &nc_ctx->t2); /* m+ <- (* m+ B) */
76289 duk__bi_mul_small_copy(&nc_ctx->mm, nc_ctx->B, &nc_ctx->t2); /* m- <- (* m- B) */
76290 DUK__BI_PRINT("mp(upd)", &nc_ctx->mp);
76291 DUK__BI_PRINT("mm(upd)", &nc_ctx->mm);
76292
76293 /* Terminating conditions. For fixed width output, we just ignore the
76294 * terminating conditions (and pretend that tc1 == tc2 == false). The
76295 * the current shortcut for fixed-format output is to generate a few
76296 * extra digits and use rounding (with carry) to finish the output.
76297 */
76298
76299 if (nc_ctx->is_fixed == 0) {
76300 /* free-form */
76301 tc1 = (duk__bi_compare(&nc_ctx->r, &nc_ctx->mm) <= (nc_ctx->low_ok ? 0 : -1));
76302
76303 duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp); /* t1 <- (+ r m+) */
76304 tc2 = (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) >= (nc_ctx->high_ok ? 0 : 1));
76305
76306 DUK_DDD(DUK_DDDPRINT("tc1=%ld, tc2=%ld", (long) tc1, (long) tc2));
76307 } else {
76308 /* fixed-format */
76309 tc1 = 0;
76310 tc2 = 0;
76311 }
76312
76313 /* Count is incremented before DUK__DRAGON4_OUTPUT_PREINC() call
76314 * on purpose, which is taken into account by the macro.
76315 */
76316 count++;
76317
76318 if (tc1) {
76319 if (tc2) {
76320 /* tc1 = true, tc2 = true */
76321 duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->r, 2);
76322 if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) < 0) { /* (< (* r 2) s) */
76323 DUK_DDD(DUK_DDDPRINT("tc1=true, tc2=true, 2r > s: output d --> %ld (k=%ld)",
76324 (long) d, (long) nc_ctx->k));
76325 DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d);
76326 } else {
76327 DUK_DDD(DUK_DDDPRINT("tc1=true, tc2=true, 2r <= s: output d+1 --> %ld (k=%ld)",
76328 (long) (d + 1), (long) nc_ctx->k));
76329 DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d + 1);
76330 }
76331 break;
76332 } else {
76333 /* tc1 = true, tc2 = false */
76334 DUK_DDD(DUK_DDDPRINT("tc1=true, tc2=false: output d --> %ld (k=%ld)",
76335 (long) d, (long) nc_ctx->k));
76336 DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d);
76337 break;
76338 }
76339 } else {
76340 if (tc2) {
76341 /* tc1 = false, tc2 = true */
76342 DUK_DDD(DUK_DDDPRINT("tc1=false, tc2=true: output d+1 --> %ld (k=%ld)",
76343 (long) (d + 1), (long) nc_ctx->k));
76344 DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d + 1);
76345 break;
76346 } else {
76347 /* tc1 = false, tc2 = false */
76348 DUK_DDD(DUK_DDDPRINT("tc1=false, tc2=false: output d --> %ld (k=%ld)",
76349 (long) d, (long) nc_ctx->k));
76350 DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d);
76351
76352 /* r <- r (updated above: r <- (remainder (* r B) s)
76353 * s <- s
76354 * m+ <- m+ (updated above: m+ <- (* m+ B)
76355 * m- <- m- (updated above: m- <- (* m- B)
76356 * B, low_ok, high_ok are fixed
76357 */
76358
76359 /* fall through and continue for-loop */
76360 }
76361 }
76362
76363 /* fixed-format termination conditions */
76364 if (nc_ctx->is_fixed) {
76365 if (nc_ctx->abs_pos) {
76366 int pos = nc_ctx->k - count + 1; /* count is already incremented, take into account */
76367 DUK_DDD(DUK_DDDPRINT("fixed format, absolute: abs pos=%ld, k=%ld, count=%ld, req=%ld",
76368 (long) pos, (long) nc_ctx->k, (long) count, (long) nc_ctx->req_digits));
76369 if (pos <= nc_ctx->req_digits) {
76370 DUK_DDD(DUK_DDDPRINT("digit position reached req_digits, end generate loop"));
76371 break;
76372 }
76373 } else {
76374 DUK_DDD(DUK_DDDPRINT("fixed format, relative: k=%ld, count=%ld, req=%ld",
76375 (long) nc_ctx->k, (long) count, (long) nc_ctx->req_digits));
76376 if (count >= nc_ctx->req_digits) {
76377 DUK_DDD(DUK_DDDPRINT("digit count reached req_digits, end generate loop"));
76378 break;
76379 }
76380 }
76381 }
76382 } /* for */
76383
76384 nc_ctx->count = count;
76385
76386 DUK_DDD(DUK_DDDPRINT("generate finished"));
76387
76388#ifdef DUK_USE_DDDPRINT
76389 {
76390 duk_uint8_t buf[2048];
76391 duk_small_int_t i, t;
76392 DUK_MEMZERO(buf, sizeof(buf));
76393 for (i = 0; i < nc_ctx->count; i++) {
76394 t = nc_ctx->digits[i];
76395 if (t < 0 || t > 36) {
76396 buf[i] = (duk_uint8_t) '?';
76397 } else {
76398 buf[i] = (duk_uint8_t) DUK__DIGITCHAR(t);
76399 }
76400 }
76401 DUK_DDD(DUK_DDDPRINT("-> generated digits; k=%ld, digits='%s'",
76402 (long) nc_ctx->k, (const char *) buf));
76403 }
76404#endif
76405}
76406
76407/* Round up digits to a given position. If position is out-of-bounds,
76408 * does nothing. If carry propagates over the first digit, a '1' is
76409 * prepended to digits and 'k' will be updated. Return value indicates
76410 * whether carry propagated over the first digit.
76411 *
76412 * Note that nc_ctx->count is NOT updated based on the rounding position
76413 * (it is updated only if carry overflows over the first digit and an
76414 * extra digit is prepended).
76415 */
76416DUK_LOCAL duk_small_int_t duk__dragon4_fixed_format_round(duk__numconv_stringify_ctx *nc_ctx, duk_small_int_t round_idx) {
76417 duk_small_int_t t;
76418 duk_uint8_t *p;
76419 duk_uint8_t roundup_limit;
76420 duk_small_int_t ret = 0;
76421
76422 /*
76423 * round_idx points to the digit which is considered for rounding; the
76424 * digit to its left is the final digit of the rounded value. If round_idx
76425 * is zero, rounding will be performed; the result will either be an empty
76426 * rounded value or if carry happens a '1' digit is generated.
76427 */
76428
76429 if (round_idx >= nc_ctx->count) {
76430 DUK_DDD(DUK_DDDPRINT("round_idx out of bounds (%ld >= %ld (count)) -> no rounding",
76431 (long) round_idx, (long) nc_ctx->count));
76432 return 0;
76433 } else if (round_idx < 0) {
76434 DUK_DDD(DUK_DDDPRINT("round_idx out of bounds (%ld < 0) -> no rounding",
76435 (long) round_idx));
76436 return 0;
76437 }
76438
76439 /*
76440 * Round-up limit.
76441 *
76442 * For even values, divides evenly, e.g. 10 -> roundup_limit=5.
76443 *
76444 * For odd values, rounds up, e.g. 3 -> roundup_limit=2.
76445 * If radix is 3, 0/3 -> down, 1/3 -> down, 2/3 -> up.
76446 */
76447 roundup_limit = (duk_uint8_t) ((nc_ctx->B + 1) / 2);
76448
76449 p = &nc_ctx->digits[round_idx];
76450 if (*p >= roundup_limit) {
76451 DUK_DDD(DUK_DDDPRINT("fixed-format rounding carry required"));
76452 /* carry */
76453 for (;;) {
76454 *p = 0;
76455 if (p == &nc_ctx->digits[0]) {
76456 DUK_DDD(DUK_DDDPRINT("carry propagated to first digit -> special case handling"));
76457 DUK_MEMMOVE((void *) (&nc_ctx->digits[1]),
11fdf7f2 76458 (const void *) (&nc_ctx->digits[0]),
7c673cae
FG
76459 (size_t) (sizeof(char) * nc_ctx->count));
76460 nc_ctx->digits[0] = 1; /* don't increase 'count' */
76461 nc_ctx->k++; /* position of highest digit changed */
76462 nc_ctx->count++; /* number of digits changed */
76463 ret = 1;
76464 break;
76465 }
76466
76467 DUK_DDD(DUK_DDDPRINT("fixed-format rounding carry: B=%ld, roundup_limit=%ld, p=%p, digits=%p",
76468 (long) nc_ctx->B, (long) roundup_limit, (void *) p, (void *) nc_ctx->digits));
76469 p--;
76470 t = *p;
76471 DUK_DDD(DUK_DDDPRINT("digit before carry: %ld", (long) t));
76472 if (++t < nc_ctx->B) {
76473 DUK_DDD(DUK_DDDPRINT("rounding carry terminated"));
11fdf7f2 76474 *p = (duk_uint8_t) t;
7c673cae
FG
76475 break;
76476 }
76477
76478 DUK_DDD(DUK_DDDPRINT("wraps, carry to next digit"));
76479 }
76480 }
76481
76482 return ret;
76483}
76484
76485#define DUK__NO_EXP (65536) /* arbitrary marker, outside valid exp range */
76486
76487DUK_LOCAL void duk__dragon4_convert_and_push(duk__numconv_stringify_ctx *nc_ctx,
76488 duk_context *ctx,
76489 duk_small_int_t radix,
76490 duk_small_int_t digits,
76491 duk_small_uint_t flags,
76492 duk_small_int_t neg) {
76493 duk_small_int_t k;
76494 duk_small_int_t pos, pos_end;
76495 duk_small_int_t expt;
76496 duk_small_int_t dig;
76497 duk_uint8_t *q;
76498 duk_uint8_t *buf;
76499
76500 /*
76501 * The string conversion here incorporates all the necessary Ecmascript
76502 * semantics without attempting to be generic. nc_ctx->digits contains
76503 * nc_ctx->count digits (>= 1), with the topmost digit's 'position'
76504 * indicated by nc_ctx->k as follows:
76505 *
76506 * digits="123" count=3 k=0 --> 0.123
76507 * digits="123" count=3 k=1 --> 1.23
76508 * digits="123" count=3 k=5 --> 12300
76509 * digits="123" count=3 k=-1 --> 0.0123
76510 *
76511 * Note that the identifier names used for format selection are different
76512 * in Burger-Dybvig paper and Ecmascript specification (quite confusingly
76513 * so, because e.g. 'k' has a totally different meaning in each). See
76514 * documentation for discussion.
76515 *
76516 * Ecmascript doesn't specify any specific behavior for format selection
76517 * (e.g. when to use exponent notation) for non-base-10 numbers.
76518 *
76519 * The bigint space in the context is reused for string output, as there
76520 * is more than enough space for that (>1kB at the moment), and we avoid
76521 * allocating even more stack.
76522 */
76523
76524 DUK_ASSERT(DUK__NUMCONV_CTX_BIGINTS_SIZE >= DUK__MAX_FORMATTED_LENGTH);
76525 DUK_ASSERT(nc_ctx->count >= 1);
76526
76527 k = nc_ctx->k;
76528 buf = (duk_uint8_t *) &nc_ctx->f; /* XXX: union would be more correct */
76529 q = buf;
76530
76531 /* Exponent handling: if exponent format is used, record exponent value and
76532 * fake k such that one leading digit is generated (e.g. digits=123 -> "1.23").
76533 *
76534 * toFixed() prevents exponent use; otherwise apply a set of criteria to
76535 * match the other API calls (toString(), toPrecision, etc).
76536 */
76537
76538 expt = DUK__NO_EXP;
76539 if (!nc_ctx->abs_pos /* toFixed() */) {
76540 if ((flags & DUK_N2S_FLAG_FORCE_EXP) || /* exponential notation forced */
76541 ((flags & DUK_N2S_FLAG_NO_ZERO_PAD) && /* fixed precision and zero padding would be required */
76542 (k - digits >= 1)) || /* (e.g. k=3, digits=2 -> "12X") */
76543 ((k > 21 || k <= -6) && (radix == 10))) { /* toString() conditions */
76544 DUK_DDD(DUK_DDDPRINT("use exponential notation: k=%ld -> expt=%ld",
76545 (long) k, (long) (k - 1)));
76546 expt = k - 1; /* e.g. 12.3 -> digits="123" k=2 -> 1.23e1 */
76547 k = 1; /* generate mantissa with a single leading whole number digit */
76548 }
76549 }
76550
76551 if (neg) {
76552 *q++ = '-';
76553 }
76554
76555 /* Start position (inclusive) and end position (exclusive) */
76556 pos = (k >= 1 ? k : 1);
76557 if (nc_ctx->is_fixed) {
76558 if (nc_ctx->abs_pos) {
76559 /* toFixed() */
76560 pos_end = -digits;
76561 } else {
76562 pos_end = k - digits;
76563 }
76564 } else {
76565 pos_end = k - nc_ctx->count;
76566 }
76567 if (pos_end > 0) {
76568 pos_end = 0;
76569 }
76570
76571 DUK_DDD(DUK_DDDPRINT("expt=%ld, k=%ld, count=%ld, pos=%ld, pos_end=%ld, is_fixed=%ld, "
76572 "digits=%ld, abs_pos=%ld",
76573 (long) expt, (long) k, (long) nc_ctx->count, (long) pos, (long) pos_end,
76574 (long) nc_ctx->is_fixed, (long) digits, (long) nc_ctx->abs_pos));
76575
76576 /* Digit generation */
76577 while (pos > pos_end) {
76578 DUK_DDD(DUK_DDDPRINT("digit generation: pos=%ld, pos_end=%ld",
76579 (long) pos, (long) pos_end));
76580 if (pos == 0) {
76581 *q++ = (duk_uint8_t) '.';
76582 }
76583 if (pos > k) {
76584 *q++ = (duk_uint8_t) '0';
76585 } else if (pos <= k - nc_ctx->count) {
76586 *q++ = (duk_uint8_t) '0';
76587 } else {
76588 dig = nc_ctx->digits[k - pos];
76589 DUK_ASSERT(dig >= 0 && dig < nc_ctx->B);
76590 *q++ = (duk_uint8_t) DUK__DIGITCHAR(dig);
76591 }
76592
76593 pos--;
76594 }
76595 DUK_ASSERT(pos <= 1);
76596
76597 /* Exponent */
76598 if (expt != DUK__NO_EXP) {
76599 /*
76600 * Exponent notation for non-base-10 numbers isn't specified in Ecmascript
76601 * specification, as it never explicitly turns up: non-decimal numbers can
76602 * only be formatted with Number.prototype.toString([radix]) and for that,
76603 * behavior is not explicitly specified.
76604 *
76605 * Logical choices include formatting the exponent as decimal (e.g. binary
76606 * 100000 as 1e+5) or in current radix (e.g. binary 100000 as 1e+101).
76607 * The Dragon4 algorithm (in the original paper) prints the exponent value
76608 * in the target radix B. However, for radix values 15 and above, the
76609 * exponent separator 'e' is no longer easily parseable. Consider, for
76610 * instance, the number "1.faecee+1c".
76611 */
76612
76613 duk_size_t len;
76614 char expt_sign;
76615
76616 *q++ = 'e';
76617 if (expt >= 0) {
76618 expt_sign = '+';
76619 } else {
76620 expt_sign = '-';
76621 expt = -expt;
76622 }
76623 *q++ = (duk_uint8_t) expt_sign;
76624 len = duk__dragon4_format_uint32(q, (duk_uint32_t) expt, radix);
76625 q += len;
76626 }
76627
76628 duk_push_lstring(ctx, (const char *) buf, (size_t) (q - buf));
76629}
76630
76631/*
76632 * Conversion helpers
76633 */
76634
76635DUK_LOCAL void duk__dragon4_double_to_ctx(duk__numconv_stringify_ctx *nc_ctx, duk_double_t x) {
76636 duk_double_union u;
76637 duk_uint32_t tmp;
76638 duk_small_int_t expt;
76639
76640 /*
76641 * seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
76642 * A B C D E F G H
76643 *
76644 * s sign bit
76645 * eee... exponent field
76646 * fff... fraction
76647 *
76648 * ieee value = 1.ffff... * 2^(e - 1023) (normal)
76649 * = 0.ffff... * 2^(-1022) (denormal)
76650 *
76651 * algorithm v = f * b^e
76652 */
76653
76654 DUK_DBLUNION_SET_DOUBLE(&u, x);
76655
76656 nc_ctx->f.n = 2;
76657
76658 tmp = DUK_DBLUNION_GET_LOW32(&u);
76659 nc_ctx->f.v[0] = tmp;
76660 tmp = DUK_DBLUNION_GET_HIGH32(&u);
76661 nc_ctx->f.v[1] = tmp & 0x000fffffUL;
76662 expt = (duk_small_int_t) ((tmp >> 20) & 0x07ffUL);
76663
76664 if (expt == 0) {
76665 /* denormal */
76666 expt = DUK__IEEE_DOUBLE_EXP_MIN - 52;
76667 duk__bi_normalize(&nc_ctx->f);
76668 } else {
76669 /* normal: implicit leading 1-bit */
76670 nc_ctx->f.v[1] |= 0x00100000UL;
76671 expt = expt - DUK__IEEE_DOUBLE_EXP_BIAS - 52;
76672 DUK_ASSERT(duk__bi_is_valid(&nc_ctx->f)); /* true, because v[1] has at least one bit set */
76673 }
76674
76675 DUK_ASSERT(duk__bi_is_valid(&nc_ctx->f));
76676
76677 nc_ctx->e = expt;
76678}
76679
76680DUK_LOCAL void duk__dragon4_ctx_to_double(duk__numconv_stringify_ctx *nc_ctx, duk_double_t *x) {
76681 duk_double_union u;
76682 duk_small_int_t expt;
76683 duk_small_int_t i;
76684 duk_small_int_t bitstart;
76685 duk_small_int_t bitround;
76686 duk_small_int_t bitidx;
76687 duk_small_int_t skip_round;
76688 duk_uint32_t t, v;
76689
76690 DUK_ASSERT(nc_ctx->count == 53 + 1);
76691
76692 /* Sometimes this assert is not true right now; it will be true after
76693 * rounding. See: test-bug-numconv-mantissa-assert.js.
76694 */
76695 DUK_ASSERT_DISABLE(nc_ctx->digits[0] == 1); /* zero handled by caller */
76696
76697 /* Should not be required because the code below always sets both high
76698 * and low parts, but at least gcc-4.4.5 fails to deduce this correctly
76699 * (perhaps because the low part is set (seemingly) conditionally in a
76700 * loop), so this is here to avoid the bogus warning.
76701 */
76702 DUK_MEMZERO((void *) &u, sizeof(u));
76703
76704 /*
76705 * Figure out how generated digits match up with the mantissa,
76706 * and then perform rounding. If mantissa overflows, need to
76707 * recompute the exponent (it is bumped and may overflow to
76708 * infinity).
76709 *
76710 * For normal numbers the leading '1' is hidden and ignored,
76711 * and the last bit is used for rounding:
76712 *
76713 * rounding pt
76714 * <--------52------->|
76715 * 1 x x x x ... x x x x|y ==> x x x x ... x x x x
76716 *
76717 * For denormals, the leading '1' is included in the number,
76718 * and the rounding point is different:
76719 *
76720 * rounding pt
76721 * <--52 or less--->|
76722 * 1 x x x x ... x x|x x y ==> 0 0 ... 1 x x ... x x
76723 *
76724 * The largest denormals will have a mantissa beginning with
76725 * a '1' (the explicit leading bit); smaller denormals will
76726 * have leading zero bits.
76727 *
76728 * If the exponent would become too high, the result becomes
76729 * Infinity. If the exponent is so small that the entire
76730 * mantissa becomes zero, the result becomes zero.
76731 *
76732 * Note: the Dragon4 'k' is off-by-one with respect to the IEEE
76733 * exponent. For instance, k==0 indicates that the leading '1'
76734 * digit is at the first binary fraction position (0.1xxx...);
76735 * the corresponding IEEE exponent would be -1.
76736 */
76737
76738 skip_round = 0;
76739
76740 recheck_exp:
76741
76742 expt = nc_ctx->k - 1; /* IEEE exp without bias */
76743 if (expt > 1023) {
76744 /* Infinity */
76745 bitstart = -255; /* needed for inf: causes mantissa to become zero,
76746 * and rounding to be skipped.
76747 */
76748 expt = 2047;
76749 } else if (expt >= -1022) {
76750 /* normal */
76751 bitstart = 1; /* skip leading digit */
76752 expt += DUK__IEEE_DOUBLE_EXP_BIAS;
76753 DUK_ASSERT(expt >= 1 && expt <= 2046);
76754 } else {
76755 /* denormal or zero */
76756 bitstart = 1023 + expt; /* expt==-1023 -> bitstart=0 (leading 1);
76757 * expt==-1024 -> bitstart=-1 (one left of leading 1), etc
76758 */
76759 expt = 0;
76760 }
76761 bitround = bitstart + 52;
76762
76763 DUK_DDD(DUK_DDDPRINT("ieee expt=%ld, bitstart=%ld, bitround=%ld",
76764 (long) expt, (long) bitstart, (long) bitround));
76765
76766 if (!skip_round) {
76767 if (duk__dragon4_fixed_format_round(nc_ctx, bitround)) {
76768 /* Corner case: see test-numconv-parse-mant-carry.js. We could
76769 * just bump the exponent and update bitstart, but it's more robust
76770 * to recompute (but avoid rounding twice).
76771 */
76772 DUK_DDD(DUK_DDDPRINT("rounding caused exponent to be bumped, recheck exponent"));
76773 skip_round = 1;
76774 goto recheck_exp;
76775 }
76776 }
76777
76778 /*
76779 * Create mantissa
76780 */
76781
76782 t = 0;
76783 for (i = 0; i < 52; i++) {
76784 bitidx = bitstart + 52 - 1 - i;
76785 if (bitidx >= nc_ctx->count) {
76786 v = 0;
76787 } else if (bitidx < 0) {
76788 v = 0;
76789 } else {
76790 v = nc_ctx->digits[bitidx];
76791 }
76792 DUK_ASSERT(v == 0 || v == 1);
76793 t += v << (i % 32);
76794 if (i == 31) {
76795 /* low 32 bits is complete */
76796 DUK_DBLUNION_SET_LOW32(&u, t);
76797 t = 0;
76798 }
76799 }
76800 /* t has high mantissa */
76801
76802 DUK_DDD(DUK_DDDPRINT("mantissa is complete: %08lx %08lx",
76803 (unsigned long) t,
76804 (unsigned long) DUK_DBLUNION_GET_LOW32(&u)));
76805
76806 DUK_ASSERT(expt >= 0 && expt <= 0x7ffL);
76807 t += expt << 20;
76808#if 0 /* caller handles sign change */
76809 if (negative) {
76810 t |= 0x80000000U;
76811 }
76812#endif
76813 DUK_DBLUNION_SET_HIGH32(&u, t);
76814
76815 DUK_DDD(DUK_DDDPRINT("number is complete: %08lx %08lx",
76816 (unsigned long) DUK_DBLUNION_GET_HIGH32(&u),
76817 (unsigned long) DUK_DBLUNION_GET_LOW32(&u)));
76818
76819 *x = DUK_DBLUNION_GET_DOUBLE(&u);
76820}
76821
76822/*
76823 * Exposed number-to-string API
76824 *
76825 * Input: [ number ]
76826 * Output: [ string ]
76827 */
76828
76829DUK_INTERNAL void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags) {
76830 duk_double_t x;
76831 duk_small_int_t c;
76832 duk_small_int_t neg;
76833 duk_uint32_t uval;
76834 duk__numconv_stringify_ctx nc_ctx_alloc; /* large context; around 2kB now */
76835 duk__numconv_stringify_ctx *nc_ctx = &nc_ctx_alloc;
76836
76837 x = (duk_double_t) duk_require_number(ctx, -1);
76838 duk_pop(ctx);
76839
76840 /*
76841 * Handle special cases (NaN, infinity, zero).
76842 */
76843
76844 c = (duk_small_int_t) DUK_FPCLASSIFY(x);
76845 if (DUK_SIGNBIT((double) x)) {
76846 x = -x;
76847 neg = 1;
76848 } else {
76849 neg = 0;
76850 }
76851
76852 /* NaN sign bit is platform specific with unpacked, un-normalized NaNs */
76853 DUK_ASSERT(c == DUK_FP_NAN || DUK_SIGNBIT((double) x) == 0);
76854
76855 if (c == DUK_FP_NAN) {
76856 duk_push_hstring_stridx(ctx, DUK_STRIDX_NAN);
76857 return;
76858 } else if (c == DUK_FP_INFINITE) {
76859 if (neg) {
76860 /* -Infinity */
76861 duk_push_hstring_stridx(ctx, DUK_STRIDX_MINUS_INFINITY);
76862 } else {
76863 /* Infinity */
76864 duk_push_hstring_stridx(ctx, DUK_STRIDX_INFINITY);
76865 }
76866 return;
76867 } else if (c == DUK_FP_ZERO) {
76868 /* We can't shortcut zero here if it goes through special formatting
76869 * (such as forced exponential notation).
76870 */
76871 ;
76872 }
76873
76874 /*
76875 * Handle integers in 32-bit range (that is, [-(2**32-1),2**32-1])
76876 * specially, as they're very likely for embedded programs. This
76877 * is now done for all radix values. We must be careful not to use
76878 * the fast path when special formatting (e.g. forced exponential)
76879 * is in force.
76880 *
76881 * XXX: could save space by supporting radix 10 only and using
76882 * sprintf "%lu" for the fast path and for exponent formatting.
76883 */
76884
76885 uval = (unsigned int) x;
76886 if (((double) uval) == x && /* integer number in range */
76887 flags == 0) { /* no special formatting */
76888 /* use bigint area as a temp */
76889 duk_uint8_t *buf = (duk_uint8_t *) (&nc_ctx->f);
76890 duk_uint8_t *p = buf;
76891
76892 DUK_ASSERT(DUK__NUMCONV_CTX_BIGINTS_SIZE >= 32 + 1); /* max size: radix=2 + sign */
76893 if (neg && uval != 0) {
76894 /* no negative sign for zero */
76895 *p++ = (duk_uint8_t) '-';
76896 }
76897 p += duk__dragon4_format_uint32(p, uval, radix);
76898 duk_push_lstring(ctx, (const char *) buf, (duk_size_t) (p - buf));
76899 return;
76900 }
76901
76902 /*
76903 * Dragon4 setup.
76904 *
76905 * Convert double from IEEE representation for conversion;
76906 * normal finite values have an implicit leading 1-bit. The
76907 * slow path algorithm doesn't handle zero, so zero is special
76908 * cased here but still creates a valid nc_ctx, and goes
76909 * through normal formatting in case special formatting has
76910 * been requested (e.g. forced exponential format: 0 -> "0e+0").
76911 */
76912
76913 /* Would be nice to bulk clear the allocation, but the context
76914 * is 1-2 kilobytes and nothing should rely on it being zeroed.
76915 */
76916#if 0
76917 DUK_MEMZERO((void *) nc_ctx, sizeof(*nc_ctx)); /* slow init, do only for slow path cases */
76918#endif
76919
76920 nc_ctx->is_s2n = 0;
76921 nc_ctx->b = 2;
76922 nc_ctx->B = radix;
76923 nc_ctx->abs_pos = 0;
76924 if (flags & DUK_N2S_FLAG_FIXED_FORMAT) {
76925 nc_ctx->is_fixed = 1;
76926 if (flags & DUK_N2S_FLAG_FRACTION_DIGITS) {
76927 /* absolute req_digits; e.g. digits = 1 -> last digit is 0,
76928 * but add an extra digit for rounding.
76929 */
76930 nc_ctx->abs_pos = 1;
76931 nc_ctx->req_digits = (-digits + 1) - 1;
76932 } else {
76933 nc_ctx->req_digits = digits + 1;
76934 }
76935 } else {
76936 nc_ctx->is_fixed = 0;
76937 nc_ctx->req_digits = 0;
76938 }
76939
76940 if (c == DUK_FP_ZERO) {
76941 /* Zero special case: fake requested number of zero digits; ensure
76942 * no sign bit is printed. Relative and absolute fixed format
76943 * require separate handling.
76944 */
76945 duk_small_int_t count;
76946 if (nc_ctx->is_fixed) {
76947 if (nc_ctx->abs_pos) {
76948 count = digits + 2; /* lead zero + 'digits' fractions + 1 for rounding */
76949 } else {
76950 count = digits + 1; /* + 1 for rounding */
76951 }
76952 } else {
76953 count = 1;
76954 }
76955 DUK_DDD(DUK_DDDPRINT("count=%ld", (long) count));
76956 DUK_ASSERT(count >= 1);
76957 DUK_MEMZERO((void *) nc_ctx->digits, count);
76958 nc_ctx->count = count;
76959 nc_ctx->k = 1; /* 0.000... */
76960 neg = 0;
76961 goto zero_skip;
76962 }
76963
76964 duk__dragon4_double_to_ctx(nc_ctx, x); /* -> sets 'f' and 'e' */
76965 DUK__BI_PRINT("f", &nc_ctx->f);
76966 DUK_DDD(DUK_DDDPRINT("e=%ld", (long) nc_ctx->e));
76967
76968 /*
76969 * Dragon4 slow path digit generation.
76970 */
76971
76972 duk__dragon4_prepare(nc_ctx); /* setup many variables in nc_ctx */
76973
76974 DUK_DDD(DUK_DDDPRINT("after prepare:"));
76975 DUK__BI_PRINT("r", &nc_ctx->r);
76976 DUK__BI_PRINT("s", &nc_ctx->s);
76977 DUK__BI_PRINT("mp", &nc_ctx->mp);
76978 DUK__BI_PRINT("mm", &nc_ctx->mm);
76979
76980 duk__dragon4_scale(nc_ctx);
76981
76982 DUK_DDD(DUK_DDDPRINT("after scale; k=%ld", (long) nc_ctx->k));
76983 DUK__BI_PRINT("r", &nc_ctx->r);
76984 DUK__BI_PRINT("s", &nc_ctx->s);
76985 DUK__BI_PRINT("mp", &nc_ctx->mp);
76986 DUK__BI_PRINT("mm", &nc_ctx->mm);
76987
76988 duk__dragon4_generate(nc_ctx);
76989
76990 /*
76991 * Convert and push final string.
76992 */
76993
76994 zero_skip:
76995
76996 if (flags & DUK_N2S_FLAG_FIXED_FORMAT) {
76997 /* Perform fixed-format rounding. */
76998 duk_small_int_t roundpos;
76999 if (flags & DUK_N2S_FLAG_FRACTION_DIGITS) {
77000 /* 'roundpos' is relative to nc_ctx->k and increases to the right
77001 * (opposite of how 'k' changes).
77002 */
77003 roundpos = -digits; /* absolute position for digit considered for rounding */
77004 roundpos = nc_ctx->k - roundpos;
77005 } else {
77006 roundpos = digits;
77007 }
77008 DUK_DDD(DUK_DDDPRINT("rounding: k=%ld, count=%ld, digits=%ld, roundpos=%ld",
77009 (long) nc_ctx->k, (long) nc_ctx->count, (long) digits, (long) roundpos));
77010 (void) duk__dragon4_fixed_format_round(nc_ctx, roundpos);
77011
77012 /* Note: 'count' is currently not adjusted by rounding (i.e. the
77013 * digits are not "chopped off". That shouldn't matter because
77014 * the digit position (absolute or relative) is passed on to the
77015 * convert-and-push function.
77016 */
77017 }
77018
77019 duk__dragon4_convert_and_push(nc_ctx, ctx, radix, digits, flags, neg);
77020}
77021
77022/*
77023 * Exposed string-to-number API
77024 *
77025 * Input: [ string ]
77026 * Output: [ number ]
77027 *
77028 * If number parsing fails, a NaN is pushed as the result. If number parsing
77029 * fails due to an internal error, an InternalError is thrown.
77030 */
77031
77032DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk_small_uint_t flags) {
77033 duk_hthread *thr = (duk_hthread *) ctx;
77034 duk__numconv_stringify_ctx nc_ctx_alloc; /* large context; around 2kB now */
77035 duk__numconv_stringify_ctx *nc_ctx = &nc_ctx_alloc;
77036 duk_double_t res;
77037 duk_hstring *h_str;
77038 duk_small_int_t expt;
77039 duk_small_int_t expt_neg;
77040 duk_small_int_t expt_adj;
77041 duk_small_int_t neg;
77042 duk_small_int_t dig;
77043 duk_small_int_t dig_whole;
77044 duk_small_int_t dig_lzero;
77045 duk_small_int_t dig_frac;
77046 duk_small_int_t dig_expt;
77047 duk_small_int_t dig_prec;
77048 const duk__exp_limits *explim;
77049 const duk_uint8_t *p;
77050 duk_small_int_t ch;
77051
77052 /* This seems to waste a lot of stack frame entries, but good compilers
77053 * will compute these as needed below. Some of these initial flags are
77054 * also modified in the code below, so they can't all be removed.
77055 */
77056 duk_small_int_t trim_white = (flags & DUK_S2N_FLAG_TRIM_WHITE);
77057 duk_small_int_t allow_expt = (flags & DUK_S2N_FLAG_ALLOW_EXP);
77058 duk_small_int_t allow_garbage = (flags & DUK_S2N_FLAG_ALLOW_GARBAGE);
77059 duk_small_int_t allow_plus = (flags & DUK_S2N_FLAG_ALLOW_PLUS);
77060 duk_small_int_t allow_minus = (flags & DUK_S2N_FLAG_ALLOW_MINUS);
77061 duk_small_int_t allow_infinity = (flags & DUK_S2N_FLAG_ALLOW_INF);
77062 duk_small_int_t allow_frac = (flags & DUK_S2N_FLAG_ALLOW_FRAC);
77063 duk_small_int_t allow_naked_frac = (flags & DUK_S2N_FLAG_ALLOW_NAKED_FRAC);
77064 duk_small_int_t allow_empty_frac = (flags & DUK_S2N_FLAG_ALLOW_EMPTY_FRAC);
77065 duk_small_int_t allow_empty = (flags & DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO);
77066 duk_small_int_t allow_leading_zero = (flags & DUK_S2N_FLAG_ALLOW_LEADING_ZERO);
77067 duk_small_int_t allow_auto_hex_int = (flags & DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT);
77068 duk_small_int_t allow_auto_oct_int = (flags & DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT);
77069
77070 DUK_DDD(DUK_DDDPRINT("parse number: %!T, radix=%ld, flags=0x%08lx",
77071 (duk_tval *) duk_get_tval(ctx, -1),
77072 (long) radix, (unsigned long) flags));
77073
77074 DUK_ASSERT(radix >= 2 && radix <= 36);
77075 DUK_ASSERT(radix - 2 < (duk_small_int_t) sizeof(duk__str2num_digits_for_radix));
77076
77077 /*
77078 * Preliminaries: trim, sign, Infinity check
77079 *
77080 * We rely on the interned string having a NUL terminator, which will
77081 * cause a parse failure wherever it is encountered. As a result, we
77082 * don't need separate pointer checks.
77083 *
77084 * There is no special parsing for 'NaN' in the specification although
77085 * 'Infinity' (with an optional sign) is allowed in some contexts.
77086 * Some contexts allow plus/minus sign, while others only allow the
77087 * minus sign (like JSON.parse()).
77088 *
77089 * Automatic hex number detection (leading '0x' or '0X') and octal
77090 * number detection (leading '0' followed by at least one octal digit)
77091 * is done here too.
77092 */
77093
77094 if (trim_white) {
77095 /* Leading / trailing whitespace is sometimes accepted and
77096 * sometimes not. After white space trimming, all valid input
77097 * characters are pure ASCII.
77098 */
77099 duk_trim(ctx, -1);
77100 }
77101 h_str = duk_require_hstring(ctx, -1);
77102 DUK_ASSERT(h_str != NULL);
77103 p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_str);
77104
77105 neg = 0;
77106 ch = *p;
77107 if (ch == (duk_small_int_t) '+') {
77108 if (!allow_plus) {
77109 DUK_DDD(DUK_DDDPRINT("parse failed: leading plus sign not allowed"));
77110 goto parse_fail;
77111 }
77112 p++;
77113 } else if (ch == (duk_small_int_t) '-') {
77114 if (!allow_minus) {
77115 DUK_DDD(DUK_DDDPRINT("parse failed: leading minus sign not allowed"));
77116 goto parse_fail;
77117 }
77118 p++;
77119 neg = 1;
77120 }
77121
77122 ch = *p;
77123 if (allow_infinity && ch == (duk_small_int_t) 'I') {
77124 /* Don't check for Infinity unless the context allows it.
77125 * 'Infinity' is a valid integer literal in e.g. base-36:
77126 *
77127 * parseInt('Infinity', 36)
77128 * 1461559270678
77129 */
77130
77131 const duk_uint8_t *q;
77132
77133 /* borrow literal Infinity from builtin string */
77134 q = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(DUK_HTHREAD_STRING_INFINITY(thr));
77135 if (DUK_STRNCMP((const char *) p, (const char *) q, 8) == 0) {
77136 if (!allow_garbage && (p[8] != (duk_uint8_t) 0)) {
77137 DUK_DDD(DUK_DDDPRINT("parse failed: trailing garbage after matching 'Infinity' not allowed"));
77138 goto parse_fail;
77139 } else {
77140 res = DUK_DOUBLE_INFINITY;
77141 goto negcheck_and_ret;
77142 }
77143 }
77144 }
77145 if (ch == (duk_small_int_t) '0') {
77146 duk_small_int_t detect_radix = 0;
77147 ch = p[1];
77148 if (allow_auto_hex_int && (ch == (duk_small_int_t) 'x' || ch == (duk_small_int_t) 'X')) {
77149 DUK_DDD(DUK_DDDPRINT("detected 0x/0X hex prefix, changing radix and preventing fractions and exponent"));
77150 detect_radix = 16;
77151 allow_empty = 0; /* interpret e.g. '0x' and '0xg' as a NaN (= parse error) */
77152 p += 2;
77153 } else if (allow_auto_oct_int && (ch >= (duk_small_int_t) '0' && ch <= (duk_small_int_t) '9')) {
77154 DUK_DDD(DUK_DDDPRINT("detected 0n oct prefix, changing radix and preventing fractions and exponent"));
77155 detect_radix = 8;
77156 allow_empty = 1; /* interpret e.g. '09' as '0', not NaN */
77157 p += 1;
77158 }
77159 if (detect_radix > 0) {
77160 radix = detect_radix;
77161 allow_expt = 0;
77162 allow_frac = 0;
77163 allow_naked_frac = 0;
77164 allow_empty_frac = 0;
77165 allow_leading_zero = 1; /* allow e.g. '0x0009' and '00077' */
77166 }
77167 }
77168
77169 /*
77170 * Scan number and setup for Dragon4.
77171 *
77172 * The fast path case is detected during setup: an integer which
77173 * can be converted without rounding, no net exponent. The fast
77174 * path could be implemented as a separate scan, but may not really
77175 * be worth it: the multiplications for building 'f' are not
77176 * expensive when 'f' is small.
77177 *
77178 * The significand ('f') must contain enough bits of (apparent)
77179 * accuracy, so that Dragon4 will generate enough binary output digits.
77180 * For decimal numbers, this means generating a 20-digit significand,
77181 * which should yield enough practical accuracy to parse IEEE doubles.
77182 * In fact, the Ecmascript specification explicitly allows an
77183 * implementation to treat digits beyond 20 as zeroes (and even
77184 * to round the 20th digit upwards). For non-decimal numbers, the
77185 * appropriate number of digits has been precomputed for comparable
77186 * accuracy.
77187 *
77188 * Digit counts:
77189 *
77190 * [ dig_lzero ]
77191 * |
77192 * .+-..---[ dig_prec ]----.
77193 * | || |
77194 * 0000123.456789012345678901234567890e+123456
77195 * | | | | | |
77196 * `--+--' `------[ dig_frac ]-------' `-+--'
77197 * | |
77198 * [ dig_whole ] [ dig_expt ]
77199 *
77200 * dig_frac and dig_expt are -1 if not present
77201 * dig_lzero is only computed for whole number part
77202 *
77203 * Parsing state
77204 *
77205 * Parsing whole part dig_frac < 0 AND dig_expt < 0
77206 * Parsing fraction part dig_frac >= 0 AND dig_expt < 0
77207 * Parsing exponent part dig_expt >= 0 (dig_frac may be < 0 or >= 0)
77208 *
77209 * Note: in case we hit an implementation limit (like exponent range),
77210 * we should throw an error, NOT return NaN or Infinity. Even with
77211 * very large exponent (or significand) values the final result may be
77212 * finite, so NaN/Infinity would be incorrect.
77213 */
77214
77215 duk__bi_set_small(&nc_ctx->f, 0);
77216 dig_prec = 0;
77217 dig_lzero = 0;
77218 dig_whole = 0;
77219 dig_frac = -1;
77220 dig_expt = -1;
77221 expt = 0;
77222 expt_adj = 0; /* essentially tracks digit position of lowest 'f' digit */
77223 expt_neg = 0;
77224 for (;;) {
77225 ch = *p++;
77226
77227 DUK_DDD(DUK_DDDPRINT("parse digits: p=%p, ch='%c' (%ld), expt=%ld, expt_adj=%ld, "
77228 "dig_whole=%ld, dig_frac=%ld, dig_expt=%ld, dig_lzero=%ld, dig_prec=%ld",
11fdf7f2 77229 (const void *) p, (int) ((ch >= 0x20 && ch <= 0x7e) ? ch : '?'), (long) ch,
7c673cae
FG
77230 (long) expt, (long) expt_adj, (long) dig_whole, (long) dig_frac,
77231 (long) dig_expt, (long) dig_lzero, (long) dig_prec));
77232 DUK__BI_PRINT("f", &nc_ctx->f);
77233
77234 /* Most common cases first. */
77235 if (ch >= (duk_small_int_t) '0' && ch <= (duk_small_int_t) '9') {
77236 dig = (int) ch - '0' + 0;
77237 } else if (ch == (duk_small_int_t) '.') {
77238 /* A leading digit is not required in some cases, e.g. accept ".123".
77239 * In other cases (JSON.parse()) a leading digit is required. This
77240 * is checked for after the loop.
77241 */
77242 if (dig_frac >= 0 || dig_expt >= 0) {
77243 if (allow_garbage) {
77244 DUK_DDD(DUK_DDDPRINT("garbage termination (invalid period)"));
77245 break;
77246 } else {
77247 DUK_DDD(DUK_DDDPRINT("parse failed: period not allowed"));
77248 goto parse_fail;
77249 }
77250 }
77251
77252 if (!allow_frac) {
77253 /* Some contexts don't allow fractions at all; this can't be a
77254 * post-check because the state ('f' and expt) would be incorrect.
77255 */
77256 if (allow_garbage) {
77257 DUK_DDD(DUK_DDDPRINT("garbage termination (invalid first period)"));
77258 break;
77259 } else {
77260 DUK_DDD(DUK_DDDPRINT("parse failed: fraction part not allowed"));
77261 }
77262 }
77263
77264 DUK_DDD(DUK_DDDPRINT("start fraction part"));
77265 dig_frac = 0;
77266 continue;
77267 } else if (ch == (duk_small_int_t) 0) {
77268 DUK_DDD(DUK_DDDPRINT("NUL termination"));
77269 break;
77270 } else if (allow_expt && dig_expt < 0 && (ch == (duk_small_int_t) 'e' || ch == (duk_small_int_t) 'E')) {
77271 /* Note: we don't parse back exponent notation for anything else
77272 * than radix 10, so this is not an ambiguous check (e.g. hex
77273 * exponent values may have 'e' either as a significand digit
77274 * or as an exponent separator).
77275 *
77276 * If the exponent separator occurs twice, 'e' will be interpreted
77277 * as a digit (= 14) and will be rejected as an invalid decimal
77278 * digit.
77279 */
77280
77281 DUK_DDD(DUK_DDDPRINT("start exponent part"));
77282
77283 /* Exponent without a sign or with a +/- sign is accepted
77284 * by all call sites (even JSON.parse()).
77285 */
77286 ch = *p;
77287 if (ch == (duk_small_int_t) '-') {
77288 expt_neg = 1;
77289 p++;
77290 } else if (ch == (duk_small_int_t) '+') {
77291 p++;
77292 }
77293 dig_expt = 0;
77294 continue;
77295 } else if (ch >= (duk_small_int_t) 'a' && ch <= (duk_small_int_t) 'z') {
77296 dig = (duk_small_int_t) (ch - (duk_small_int_t) 'a' + 0x0a);
77297 } else if (ch >= (duk_small_int_t) 'A' && ch <= (duk_small_int_t) 'Z') {
77298 dig = (duk_small_int_t) (ch - (duk_small_int_t) 'A' + 0x0a);
77299 } else {
77300 dig = 255; /* triggers garbage digit check below */
77301 }
77302 DUK_ASSERT((dig >= 0 && dig <= 35) || dig == 255);
77303
77304 if (dig >= radix) {
77305 if (allow_garbage) {
77306 DUK_DDD(DUK_DDDPRINT("garbage termination"));
77307 break;
77308 } else {
77309 DUK_DDD(DUK_DDDPRINT("parse failed: trailing garbage or invalid digit"));
77310 goto parse_fail;
77311 }
77312 }
77313
77314 if (dig_expt < 0) {
77315 /* whole or fraction digit */
77316
77317 if (dig_prec < duk__str2num_digits_for_radix[radix - 2]) {
77318 /* significant from precision perspective */
77319
77320 duk_small_int_t f_zero = duk__bi_is_zero(&nc_ctx->f);
77321 if (f_zero && dig == 0) {
77322 /* Leading zero is not counted towards precision digits; not
77323 * in the integer part, nor in the fraction part.
77324 */
77325 if (dig_frac < 0) {
77326 dig_lzero++;
77327 }
77328 } else {
77329 /* XXX: join these ops (multiply-accumulate), but only if
77330 * code footprint decreases.
77331 */
77332 duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, radix);
77333 duk__bi_add_small(&nc_ctx->f, &nc_ctx->t1, dig);
77334 dig_prec++;
77335 }
77336 } else {
77337 /* Ignore digits beyond a radix-specific limit, but note them
77338 * in expt_adj.
77339 */
77340 expt_adj++;
77341 }
77342
77343 if (dig_frac >= 0) {
77344 dig_frac++;
77345 expt_adj--;
77346 } else {
77347 dig_whole++;
77348 }
77349 } else {
77350 /* exponent digit */
77351
77352 expt = expt * radix + dig;
77353 if (expt > DUK_S2N_MAX_EXPONENT) {
77354 /* impose a reasonable exponent limit, so that exp
77355 * doesn't need to get tracked using a bigint.
77356 */
77357 DUK_DDD(DUK_DDDPRINT("parse failed: exponent too large"));
11fdf7f2 77358 goto parse_explimit_error;
7c673cae
FG
77359 }
77360 dig_expt++;
77361 }
77362 }
77363
77364 /* Leading zero. */
77365
77366 if (dig_lzero > 0 && dig_whole > 1) {
77367 if (!allow_leading_zero) {
77368 DUK_DDD(DUK_DDDPRINT("parse failed: leading zeroes not allowed in integer part"));
77369 goto parse_fail;
77370 }
77371 }
77372
77373 /* Validity checks for various fraction formats ("0.1", ".1", "1.", "."). */
77374
77375 if (dig_whole == 0) {
77376 if (dig_frac == 0) {
77377 /* "." is not accepted in any format */
77378 DUK_DDD(DUK_DDDPRINT("parse failed: plain period without leading or trailing digits"));
77379 goto parse_fail;
77380 } else if (dig_frac > 0) {
77381 /* ".123" */
77382 if (!allow_naked_frac) {
77383 DUK_DDD(DUK_DDDPRINT("parse failed: fraction part not allowed without "
77384 "leading integer digit(s)"));
77385 goto parse_fail;
77386 }
77387 } else {
77388 /* empty ("") is allowed in some formats (e.g. Number(''), as zero */
77389 if (!allow_empty) {
77390 DUK_DDD(DUK_DDDPRINT("parse failed: empty string not allowed (as zero)"));
77391 goto parse_fail;
77392 }
77393 }
77394 } else {
77395 if (dig_frac == 0) {
77396 /* "123." is allowed in some formats */
77397 if (!allow_empty_frac) {
77398 DUK_DDD(DUK_DDDPRINT("parse failed: empty fractions"));
77399 goto parse_fail;
77400 }
77401 } else if (dig_frac > 0) {
77402 /* "123.456" */
77403 ;
77404 } else {
77405 /* "123" */
77406 ;
77407 }
77408 }
77409
77410 /* Exponent without digits (e.g. "1e" or "1e+"). If trailing garbage is
77411 * allowed, ignore exponent part as garbage (= parse as "1", i.e. exp 0).
77412 */
77413
77414 if (dig_expt == 0) {
77415 if (!allow_garbage) {
77416 DUK_DDD(DUK_DDDPRINT("parse failed: empty exponent"));
77417 goto parse_fail;
77418 }
77419 DUK_ASSERT(expt == 0);
77420 }
77421
77422 if (expt_neg) {
77423 expt = -expt;
77424 }
77425 DUK_DDD(DUK_DDDPRINT("expt=%ld, expt_adj=%ld, net exponent -> %ld",
77426 (long) expt, (long) expt_adj, (long) (expt + expt_adj)));
77427 expt += expt_adj;
77428
77429 /* Fast path check. */
77430
77431 if (nc_ctx->f.n <= 1 && /* 32-bit value */
77432 expt == 0 /* no net exponent */) {
77433 /* Fast path is triggered for no exponent and also for balanced exponent
77434 * and fraction parts, e.g. for "1.23e2" == "123". Remember to respect
77435 * zero sign.
77436 */
77437
77438 /* XXX: could accept numbers larger than 32 bits, e.g. up to 53 bits? */
77439 DUK_DDD(DUK_DDDPRINT("fast path number parse"));
77440 if (nc_ctx->f.n == 1) {
77441 res = (double) nc_ctx->f.v[0];
77442 } else {
77443 res = 0.0;
77444 }
77445 goto negcheck_and_ret;
77446 }
77447
77448 /* Significand ('f') padding. */
77449
77450 while (dig_prec < duk__str2num_digits_for_radix[radix - 2]) {
77451 /* Pad significand with "virtual" zero digits so that Dragon4 will
77452 * have enough (apparent) precision to work with.
77453 */
77454 DUK_DDD(DUK_DDDPRINT("dig_prec=%ld, pad significand with zero", (long) dig_prec));
77455 duk__bi_mul_small_copy(&nc_ctx->f, radix, &nc_ctx->t1);
77456 DUK__BI_PRINT("f", &nc_ctx->f);
77457 expt--;
77458 dig_prec++;
77459 }
77460
77461 DUK_DDD(DUK_DDDPRINT("final exponent: %ld", (long) expt));
77462
77463 /* Detect zero special case. */
77464
77465 if (nc_ctx->f.n == 0) {
77466 /* This may happen even after the fast path check, if exponent is
77467 * not balanced (e.g. "0e1"). Remember to respect zero sign.
77468 */
77469 DUK_DDD(DUK_DDDPRINT("significand is zero"));
77470 res = 0.0;
77471 goto negcheck_and_ret;
77472 }
77473
77474
77475 /* Quick reject of too large or too small exponents. This check
77476 * would be incorrect for zero (e.g. "0e1000" is zero, not Infinity)
77477 * so zero check must be above.
77478 */
77479
77480 explim = &duk__str2num_exp_limits[radix - 2];
77481 if (expt > explim->upper) {
77482 DUK_DDD(DUK_DDDPRINT("exponent too large -> infinite"));
77483 res = (duk_double_t) DUK_DOUBLE_INFINITY;
77484 goto negcheck_and_ret;
77485 } else if (expt < explim->lower) {
77486 DUK_DDD(DUK_DDDPRINT("exponent too small -> zero"));
77487 res = (duk_double_t) 0.0;
77488 goto negcheck_and_ret;
77489 }
77490
77491 nc_ctx->is_s2n = 1;
77492 nc_ctx->e = expt;
77493 nc_ctx->b = radix;
77494 nc_ctx->B = 2;
77495 nc_ctx->is_fixed = 1;
77496 nc_ctx->abs_pos = 0;
77497 nc_ctx->req_digits = 53 + 1;
77498
77499 DUK__BI_PRINT("f", &nc_ctx->f);
77500 DUK_DDD(DUK_DDDPRINT("e=%ld", (long) nc_ctx->e));
77501
77502 /*
77503 * Dragon4 slow path (binary) digit generation.
77504 * An extra digit is generated for rounding.
77505 */
77506
77507 duk__dragon4_prepare(nc_ctx); /* setup many variables in nc_ctx */
77508
77509 DUK_DDD(DUK_DDDPRINT("after prepare:"));
77510 DUK__BI_PRINT("r", &nc_ctx->r);
77511 DUK__BI_PRINT("s", &nc_ctx->s);
77512 DUK__BI_PRINT("mp", &nc_ctx->mp);
77513 DUK__BI_PRINT("mm", &nc_ctx->mm);
77514
77515 duk__dragon4_scale(nc_ctx);
77516
77517 DUK_DDD(DUK_DDDPRINT("after scale; k=%ld", (long) nc_ctx->k));
77518 DUK__BI_PRINT("r", &nc_ctx->r);
77519 DUK__BI_PRINT("s", &nc_ctx->s);
77520 DUK__BI_PRINT("mp", &nc_ctx->mp);
77521 DUK__BI_PRINT("mm", &nc_ctx->mm);
77522
77523 duk__dragon4_generate(nc_ctx);
77524
77525 DUK_ASSERT(nc_ctx->count == 53 + 1);
77526
77527 /*
77528 * Convert binary digits into an IEEE double. Need to handle
77529 * denormals and rounding correctly.
77530 */
77531
77532 duk__dragon4_ctx_to_double(nc_ctx, &res);
77533 goto negcheck_and_ret;
77534
77535 negcheck_and_ret:
77536 if (neg) {
77537 res = -res;
77538 }
77539 duk_pop(ctx);
77540 duk_push_number(ctx, (double) res);
77541 DUK_DDD(DUK_DDDPRINT("result: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
77542 return;
77543
77544 parse_fail:
77545 DUK_DDD(DUK_DDDPRINT("parse failed"));
77546 duk_pop(ctx);
77547 duk_push_nan(ctx);
77548 return;
77549
11fdf7f2 77550 parse_explimit_error:
7c673cae 77551 DUK_DDD(DUK_DDDPRINT("parse failed, internal error, can't return a value"));
11fdf7f2 77552 DUK_ERROR_RANGE(thr, "exponent too large");
7c673cae
FG
77553 return;
77554}
7c673cae
FG
77555/*
77556 * Regexp compilation.
77557 *
77558 * See doc/regexp.rst for a discussion of the compilation approach and
77559 * current limitations.
77560 *
77561 * Regexp bytecode assumes jumps can be expressed with signed 32-bit
77562 * integers. Consequently the bytecode size must not exceed 0x7fffffffL.
77563 * The implementation casts duk_size_t (buffer size) to duk_(u)int32_t
77564 * in many places. Although this could be changed, the bytecode format
77565 * limit would still prevent regexps exceeding the signed 32-bit limit
77566 * from working.
77567 *
77568 * XXX: The implementation does not prevent bytecode from exceeding the
77569 * maximum supported size. This could be done by limiting the maximum
77570 * input string size (assuming an upper bound can be computed for number
77571 * of bytecode bytes emitted per input byte) or checking buffer maximum
77572 * size when emitting bytecode (slower).
77573 */
77574
77575/* include removed: duk_internal.h */
77576
77577#ifdef DUK_USE_REGEXP_SUPPORT
77578
77579/*
77580 * Helper macros
77581 */
77582
77583#define DUK__RE_INITIAL_BUFSIZE 64
77584
77585#undef DUK__RE_BUFLEN
77586#define DUK__RE_BUFLEN(re_ctx) \
77587 DUK_BW_GET_SIZE(re_ctx->thr, &re_ctx->bw)
77588
77589/*
77590 * Disjunction struct: result of parsing a disjunction
77591 */
77592
77593typedef struct {
77594 /* Number of characters that the atom matches (e.g. 3 for 'abc'),
77595 * -1 if atom is complex and number of matched characters either
77596 * varies or is not known.
77597 */
77598 duk_int32_t charlen;
77599
77600#if 0
77601 /* These are not needed to implement quantifier capture handling,
77602 * but might be needed at some point.
77603 */
77604
77605 /* re_ctx->captures at start and end of atom parsing.
77606 * Since 'captures' indicates highest capture number emitted
77607 * so far in a DUK_REOP_SAVE, the captures numbers saved by
77608 * the atom are: ]start_captures,end_captures].
77609 */
77610 duk_uint32_t start_captures;
77611 duk_uint32_t end_captures;
77612#endif
77613} duk__re_disjunction_info;
77614
77615/*
77616 * Encoding helpers
77617 *
77618 * Some of the typing is bytecode based, e.g. slice sizes are unsigned 32-bit
77619 * even though the buffer operations will use duk_size_t.
77620 */
77621
77622/* XXX: the insert helpers should ensure that the bytecode result is not
77623 * larger than expected (or at least assert for it). Many things in the
77624 * bytecode, like skip offsets, won't work correctly if the bytecode is
77625 * larger than say 2G.
77626 */
77627
77628DUK_LOCAL duk_uint32_t duk__encode_i32(duk_int32_t x) {
77629 if (x < 0) {
77630 return ((duk_uint32_t) (-x)) * 2 + 1;
77631 } else {
77632 return ((duk_uint32_t) x) * 2;
77633 }
77634}
77635
77636/* XXX: return type should probably be duk_size_t, or explicit checks are needed for
77637 * maximum size.
77638 */
77639DUK_LOCAL duk_uint32_t duk__insert_u32(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_uint32_t x) {
77640 duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH];
77641 duk_small_int_t len;
77642
77643 len = duk_unicode_encode_xutf8((duk_ucodepoint_t) x, buf);
77644 DUK_BW_INSERT_ENSURE_BYTES(re_ctx->thr, &re_ctx->bw, offset, buf, len);
77645 return (duk_uint32_t) len;
77646}
77647
77648DUK_LOCAL duk_uint32_t duk__append_u32(duk_re_compiler_ctx *re_ctx, duk_uint32_t x) {
77649 duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH];
77650 duk_small_int_t len;
77651
77652 len = duk_unicode_encode_xutf8((duk_ucodepoint_t) x, buf);
77653 DUK_BW_WRITE_ENSURE_BYTES(re_ctx->thr, &re_ctx->bw, buf, len);
77654 return (duk_uint32_t) len;
77655}
77656
77657DUK_LOCAL duk_uint32_t duk__insert_i32(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_int32_t x) {
77658 return duk__insert_u32(re_ctx, offset, duk__encode_i32(x));
77659}
77660
77661#if 0 /* unused */
77662DUK_LOCAL duk_uint32_t duk__append_i32(duk_re_compiler_ctx *re_ctx, duk_int32_t x) {
77663 return duk__append_u32(re_ctx, duk__encode_i32(x));
77664}
77665#endif
77666
77667/* special helper for emitting u16 lists (used for character ranges for built-in char classes) */
11fdf7f2 77668DUK_LOCAL void duk__append_u16_list(duk_re_compiler_ctx *re_ctx, const duk_uint16_t *values, duk_uint32_t count) {
7c673cae
FG
77669 /* Call sites don't need the result length so it's not accumulated. */
77670 while (count > 0) {
77671 (void) duk__append_u32(re_ctx, (duk_uint32_t) (*values++));
77672 count--;
77673 }
77674}
77675
77676DUK_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) {
77677 DUK_BW_INSERT_ENSURE_SLICE(re_ctx->thr, &re_ctx->bw, offset, data_offset, data_length);
77678}
77679
77680DUK_LOCAL void duk__append_slice(duk_re_compiler_ctx *re_ctx, duk_uint32_t data_offset, duk_uint32_t data_length) {
77681 DUK_BW_WRITE_ENSURE_SLICE(re_ctx->thr, &re_ctx->bw, data_offset, data_length);
77682}
77683
77684DUK_LOCAL void duk__remove_slice(duk_re_compiler_ctx *re_ctx, duk_uint32_t data_offset, duk_uint32_t data_length) {
77685 DUK_BW_REMOVE_ENSURE_SLICE(re_ctx->thr, &re_ctx->bw, data_offset, data_length);
77686}
77687
77688/*
77689 * Insert a jump offset at 'offset' to complete an instruction
77690 * (the jump offset is always the last component of an instruction).
77691 * The 'skip' argument must be computed relative to 'offset',
77692 * -without- taking into account the skip field being inserted.
77693 *
77694 * ... A B C ins X Y Z ... (ins may be a JUMP, SPLIT1/SPLIT2, etc)
77695 * => ... A B C ins SKIP X Y Z
77696 *
77697 * Computing the final (adjusted) skip value, which is relative to the
77698 * first byte of the next instruction, is a bit tricky because of the
77699 * variable length UTF-8 encoding. See doc/regexp.rst for discussion.
77700 */
77701DUK_LOCAL duk_uint32_t duk__insert_jump_offset(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_int32_t skip) {
77702 duk_small_int_t len;
77703
77704 /* XXX: solve into closed form (smaller code) */
77705
77706 if (skip < 0) {
77707 /* two encoding attempts suffices */
77708 len = duk_unicode_get_xutf8_length((duk_codepoint_t) duk__encode_i32(skip));
77709 len = duk_unicode_get_xutf8_length((duk_codepoint_t) duk__encode_i32(skip - (duk_int32_t) len));
77710 DUK_ASSERT(duk_unicode_get_xutf8_length(duk__encode_i32(skip - (duk_int32_t) len)) == len); /* no change */
77711 skip -= (duk_int32_t) len;
77712 }
77713 return duk__insert_i32(re_ctx, offset, skip);
77714}
77715
77716DUK_LOCAL duk_uint32_t duk__append_jump_offset(duk_re_compiler_ctx *re_ctx, duk_int32_t skip) {
77717 return (duk_uint32_t) duk__insert_jump_offset(re_ctx, (duk_uint32_t) DUK__RE_BUFLEN(re_ctx), skip);
77718}
77719
77720/*
77721 * duk_re_range_callback for generating character class ranges.
77722 *
77723 * When ignoreCase is false, the range is simply emitted as is.
77724 * We don't, for instance, eliminate duplicates or overlapping
77725 * ranges in a character class.
77726 *
77727 * When ignoreCase is true, the range needs to be normalized through
77728 * canonicalization. Unfortunately a canonicalized version of a
77729 * continuous range is not necessarily continuous (e.g. [x-{] is
77730 * continuous but [X-{] is not). The current algorithm creates the
77731 * canonicalized range(s) space efficiently at the cost of compile
77732 * time execution time (see doc/regexp.rst for discussion).
77733 *
77734 * Note that the ctx->nranges is a context-wide temporary value
77735 * (this is OK because there cannot be multiple character classes
77736 * being parsed simultaneously).
77737 */
77738
77739DUK_LOCAL void duk__generate_ranges(void *userdata, duk_codepoint_t r1, duk_codepoint_t r2, duk_bool_t direct) {
77740 duk_re_compiler_ctx *re_ctx = (duk_re_compiler_ctx *) userdata;
77741
77742 DUK_DD(DUK_DDPRINT("duk__generate_ranges(): re_ctx=%p, range=[%ld,%ld] direct=%ld",
77743 (void *) re_ctx, (long) r1, (long) r2, (long) direct));
77744
77745 if (!direct && (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE)) {
77746 /*
77747 * Canonicalize a range, generating result ranges as necessary.
77748 * Needs to exhaustively scan the entire range (at most 65536
77749 * code points). If 'direct' is set, caller (lexer) has ensured
77750 * that the range is already canonicalization compatible (this
77751 * is used to avoid unnecessary canonicalization of built-in
77752 * ranges like \W, which are not affected by canonicalization).
77753 *
77754 * NOTE: here is one place where we don't want to support chars
77755 * outside the BMP, because the exhaustive search would be
77756 * massively larger.
77757 */
77758
77759 duk_codepoint_t i;
77760 duk_codepoint_t t;
77761 duk_codepoint_t r_start, r_end;
77762
77763 r_start = duk_unicode_re_canonicalize_char(re_ctx->thr, r1);
77764 r_end = r_start;
77765 for (i = r1 + 1; i <= r2; i++) {
77766 t = duk_unicode_re_canonicalize_char(re_ctx->thr, i);
77767 if (t == r_end + 1) {
77768 r_end = t;
77769 } else {
77770 DUK_DD(DUK_DDPRINT("canonicalized, emit range: [%ld,%ld]", (long) r_start, (long) r_end));
77771 duk__append_u32(re_ctx, (duk_uint32_t) r_start);
77772 duk__append_u32(re_ctx, (duk_uint32_t) r_end);
77773 re_ctx->nranges++;
77774 r_start = t;
77775 r_end = t;
77776 }
77777 }
77778 DUK_DD(DUK_DDPRINT("canonicalized, emit range: [%ld,%ld]", (long) r_start, (long) r_end));
77779 duk__append_u32(re_ctx, (duk_uint32_t) r_start);
77780 duk__append_u32(re_ctx, (duk_uint32_t) r_end);
77781 re_ctx->nranges++;
77782 } else {
77783 DUK_DD(DUK_DDPRINT("direct, emit range: [%ld,%ld]", (long) r1, (long) r2));
77784 duk__append_u32(re_ctx, (duk_uint32_t) r1);
77785 duk__append_u32(re_ctx, (duk_uint32_t) r2);
77786 re_ctx->nranges++;
77787 }
77788}
77789
77790/*
77791 * Parse regexp Disjunction. Most of regexp compilation happens here.
77792 *
77793 * Handles Disjunction, Alternative, and Term productions directly without
77794 * recursion. The only constructs requiring recursion are positive/negative
77795 * lookaheads, capturing parentheses, and non-capturing parentheses.
77796 *
77797 * The function determines whether the entire disjunction is a 'simple atom'
77798 * (see doc/regexp.rst discussion on 'simple quantifiers') and if so,
77799 * returns the atom character length which is needed by the caller to keep
77800 * track of its own atom character length. A disjunction with more than one
77801 * alternative is never considered a simple atom (although in some cases
77802 * that might be the case).
77803 *
77804 * Return value: simple atom character length or < 0 if not a simple atom.
77805 * Appends the bytecode for the disjunction matcher to the end of the temp
77806 * buffer.
77807 *
77808 * Regexp top level structure is:
77809 *
77810 * Disjunction = Term*
77811 * | Term* | Disjunction
77812 *
77813 * Term = Assertion
77814 * | Atom
77815 * | Atom Quantifier
77816 *
77817 * An empty Term sequence is a valid disjunction alternative (e.g. /|||c||/).
77818 *
77819 * Notes:
77820 *
77821 * * Tracking of the 'simple-ness' of the current atom vs. the entire
77822 * disjunction are separate matters. For instance, the disjunction
77823 * may be complex, but individual atoms may be simple. Furthermore,
77824 * simple quantifiers are used whenever possible, even if the
77825 * disjunction as a whole is complex.
77826 *
77827 * * The estimate of whether an atom is simple is conservative now,
77828 * and it would be possible to expand it. For instance, captures
77829 * cause the disjunction to be marked complex, even though captures
77830 * -can- be handled by simple quantifiers with some minor modifications.
77831 *
77832 * * Disjunction 'tainting' as 'complex' is handled at the end of the
77833 * main for loop collectively for atoms. Assertions, quantifiers,
77834 * and '|' tokens need to taint the result manually if necessary.
77835 * Assertions cannot add to result char length, only atoms (and
77836 * quantifiers) can; currently quantifiers will taint the result
77837 * as complex though.
77838 */
77839
77840DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t expect_eof, duk__re_disjunction_info *out_atom_info) {
77841 duk_int32_t atom_start_offset = -1; /* negative -> no atom matched on previous round */
77842 duk_int32_t atom_char_length = 0; /* negative -> complex atom */
77843 duk_uint32_t atom_start_captures = re_ctx->captures; /* value of re_ctx->captures at start of atom */
77844 duk_int32_t unpatched_disjunction_split = -1;
77845 duk_int32_t unpatched_disjunction_jump = -1;
77846 duk_uint32_t entry_offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx);
77847 duk_int32_t res_charlen = 0; /* -1 if disjunction is complex, char length if simple */
77848 duk__re_disjunction_info tmp_disj;
77849
77850 DUK_ASSERT(out_atom_info != NULL);
77851
77852 if (re_ctx->recursion_depth >= re_ctx->recursion_limit) {
11fdf7f2 77853 DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_REGEXP_COMPILER_RECURSION_LIMIT);
7c673cae
FG
77854 }
77855 re_ctx->recursion_depth++;
77856
77857#if 0
77858 out_atom_info->start_captures = re_ctx->captures;
77859#endif
77860
77861 for (;;) {
77862 /* atom_char_length, atom_start_offset, atom_start_offset reflect the
77863 * atom matched on the previous loop. If a quantifier is encountered
77864 * on this loop, these are needed to handle the quantifier correctly.
77865 * new_atom_char_length etc are for the atom parsed on this round;
77866 * they're written to atom_char_length etc at the end of the round.
77867 */
77868 duk_int32_t new_atom_char_length; /* char length of the atom parsed in this loop */
77869 duk_int32_t new_atom_start_offset; /* bytecode start offset of the atom parsed in this loop
77870 * (allows quantifiers to copy the atom bytecode)
77871 */
77872 duk_uint32_t new_atom_start_captures; /* re_ctx->captures at the start of the atom parsed in this loop */
77873
77874 duk_lexer_parse_re_token(&re_ctx->lex, &re_ctx->curr_token);
77875
77876 DUK_DD(DUK_DDPRINT("re token: %ld (num=%ld, char=%c)",
77877 (long) re_ctx->curr_token.t,
77878 (long) re_ctx->curr_token.num,
77879 (re_ctx->curr_token.num >= 0x20 && re_ctx->curr_token.num <= 0x7e) ?
77880 (int) re_ctx->curr_token.num : (int) '?'));
77881
77882 /* set by atom case clauses */
77883 new_atom_start_offset = -1;
77884 new_atom_char_length = -1;
77885 new_atom_start_captures = re_ctx->captures;
77886
77887 switch (re_ctx->curr_token.t) {
77888 case DUK_RETOK_DISJUNCTION: {
77889 /*
77890 * The handling here is a bit tricky. If a previous '|' has been processed,
77891 * we have a pending split1 and a pending jump (for a previous match). These
77892 * need to be back-patched carefully. See docs for a detailed example.
77893 */
77894
77895 /* patch pending jump and split */
77896 if (unpatched_disjunction_jump >= 0) {
77897 duk_uint32_t offset;
77898
77899 DUK_ASSERT(unpatched_disjunction_split >= 0);
77900 offset = unpatched_disjunction_jump;
77901 offset += duk__insert_jump_offset(re_ctx,
77902 offset,
77903 (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - offset));
77904 /* offset is now target of the pending split (right after jump) */
77905 duk__insert_jump_offset(re_ctx,
77906 unpatched_disjunction_split,
77907 offset - unpatched_disjunction_split);
77908 }
77909
77910 /* add a new pending split to the beginning of the entire disjunction */
77911 (void) duk__insert_u32(re_ctx,
77912 entry_offset,
77913 DUK_REOP_SPLIT1); /* prefer direct execution */
77914 unpatched_disjunction_split = entry_offset + 1; /* +1 for opcode */
77915
77916 /* add a new pending match jump for latest finished alternative */
77917 duk__append_u32(re_ctx, DUK_REOP_JUMP);
77918 unpatched_disjunction_jump = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
77919
77920 /* 'taint' result as complex */
77921 res_charlen = -1;
77922 break;
77923 }
77924 case DUK_RETOK_QUANTIFIER: {
77925 if (atom_start_offset < 0) {
11fdf7f2 77926 DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_INVALID_QUANTIFIER_NO_ATOM);
7c673cae
FG
77927 }
77928 if (re_ctx->curr_token.qmin > re_ctx->curr_token.qmax) {
11fdf7f2 77929 DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_INVALID_QUANTIFIER_VALUES);
7c673cae
FG
77930 }
77931 if (atom_char_length >= 0) {
77932 /*
77933 * Simple atom
77934 *
77935 * If atom_char_length is zero, we'll have unbounded execution time for e.g.
77936 * /()*x/.exec('x'). We can't just skip the match because it might have some
77937 * side effects (for instance, if we allowed captures in simple atoms, the
77938 * capture needs to happen). The simple solution below is to force the
77939 * quantifier to match at most once, since the additional matches have no effect.
77940 *
77941 * With a simple atom there can be no capture groups, so no captures need
77942 * to be reset.
77943 */
77944 duk_int32_t atom_code_length;
77945 duk_uint32_t offset;
77946 duk_uint32_t qmin, qmax;
77947
77948 qmin = re_ctx->curr_token.qmin;
77949 qmax = re_ctx->curr_token.qmax;
77950 if (atom_char_length == 0) {
77951 /* qmin and qmax will be 0 or 1 */
77952 if (qmin > 1) {
77953 qmin = 1;
77954 }
77955 if (qmax > 1) {
77956 qmax = 1;
77957 }
77958 }
77959
77960 duk__append_u32(re_ctx, DUK_REOP_MATCH); /* complete 'sub atom' */
77961 atom_code_length = (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - atom_start_offset);
77962
77963 offset = atom_start_offset;
77964 if (re_ctx->curr_token.greedy) {
77965 offset += duk__insert_u32(re_ctx, offset, DUK_REOP_SQGREEDY);
77966 offset += duk__insert_u32(re_ctx, offset, qmin);
77967 offset += duk__insert_u32(re_ctx, offset, qmax);
77968 offset += duk__insert_u32(re_ctx, offset, atom_char_length);
77969 offset += duk__insert_jump_offset(re_ctx, offset, atom_code_length);
77970 } else {
77971 offset += duk__insert_u32(re_ctx, offset, DUK_REOP_SQMINIMAL);
77972 offset += duk__insert_u32(re_ctx, offset, qmin);
77973 offset += duk__insert_u32(re_ctx, offset, qmax);
77974 offset += duk__insert_jump_offset(re_ctx, offset, atom_code_length);
77975 }
77976 DUK_UNREF(offset); /* silence scan-build warning */
77977 } else {
77978 /*
77979 * Complex atom
77980 *
77981 * The original code is used as a template, and removed at the end
77982 * (this differs from the handling of simple quantifiers).
77983 *
77984 * NOTE: there is no current solution for empty atoms in complex
77985 * quantifiers. This would need some sort of a 'progress' instruction.
77986 *
77987 * XXX: impose limit on maximum result size, i.e. atom_code_len * atom_copies?
77988 */
77989 duk_int32_t atom_code_length;
77990 duk_uint32_t atom_copies;
77991 duk_uint32_t tmp_qmin, tmp_qmax;
77992
77993 /* pre-check how many atom copies we're willing to make (atom_copies not needed below) */
77994 atom_copies = (re_ctx->curr_token.qmax == DUK_RE_QUANTIFIER_INFINITE) ?
77995 re_ctx->curr_token.qmin : re_ctx->curr_token.qmax;
77996 if (atom_copies > DUK_RE_MAX_ATOM_COPIES) {
11fdf7f2 77997 DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_QUANTIFIER_TOO_MANY_COPIES);
7c673cae
FG
77998 }
77999
78000 /* wipe the capture range made by the atom (if any) */
78001 DUK_ASSERT(atom_start_captures <= re_ctx->captures);
78002 if (atom_start_captures != re_ctx->captures) {
78003 DUK_ASSERT(atom_start_captures < re_ctx->captures);
78004 DUK_DDD(DUK_DDDPRINT("must wipe ]atom_start_captures,re_ctx->captures]: ]%ld,%ld]",
78005 (long) atom_start_captures, (long) re_ctx->captures));
78006
78007 /* insert (DUK_REOP_WIPERANGE, start, count) in reverse order so the order ends up right */
78008 duk__insert_u32(re_ctx, atom_start_offset, (re_ctx->captures - atom_start_captures) * 2);
78009 duk__insert_u32(re_ctx, atom_start_offset, (atom_start_captures + 1) * 2);
78010 duk__insert_u32(re_ctx, atom_start_offset, DUK_REOP_WIPERANGE);
78011 } else {
78012 DUK_DDD(DUK_DDDPRINT("no need to wipe captures: atom_start_captures == re_ctx->captures == %ld",
78013 (long) atom_start_captures));
78014 }
78015
78016 atom_code_length = (duk_int32_t) DUK__RE_BUFLEN(re_ctx) - atom_start_offset;
78017
78018 /* insert the required matches (qmin) by copying the atom */
78019 tmp_qmin = re_ctx->curr_token.qmin;
78020 tmp_qmax = re_ctx->curr_token.qmax;
78021 while (tmp_qmin > 0) {
78022 duk__append_slice(re_ctx, atom_start_offset, atom_code_length);
78023 tmp_qmin--;
78024 if (tmp_qmax != DUK_RE_QUANTIFIER_INFINITE) {
78025 tmp_qmax--;
78026 }
78027 }
78028 DUK_ASSERT(tmp_qmin == 0);
78029
78030 /* insert code for matching the remainder - infinite or finite */
78031 if (tmp_qmax == DUK_RE_QUANTIFIER_INFINITE) {
78032 /* reuse last emitted atom for remaining 'infinite' quantifier */
78033
78034 if (re_ctx->curr_token.qmin == 0) {
78035 /* Special case: original qmin was zero so there is nothing
78036 * to repeat. Emit an atom copy but jump over it here.
78037 */
78038 duk__append_u32(re_ctx, DUK_REOP_JUMP);
78039 duk__append_jump_offset(re_ctx, atom_code_length);
78040 duk__append_slice(re_ctx, atom_start_offset, atom_code_length);
78041 }
78042 if (re_ctx->curr_token.greedy) {
78043 duk__append_u32(re_ctx, DUK_REOP_SPLIT2); /* prefer jump */
78044 } else {
78045 duk__append_u32(re_ctx, DUK_REOP_SPLIT1); /* prefer direct */
78046 }
78047 duk__append_jump_offset(re_ctx, -atom_code_length - 1); /* -1 for opcode */
78048 } else {
78049 /*
78050 * The remaining matches are emitted as sequence of SPLITs and atom
78051 * copies; the SPLITs skip the remaining copies and match the sequel.
78052 * This sequence needs to be emitted starting from the last copy
78053 * because the SPLITs are variable length due to the variable length
78054 * skip offset. This causes a lot of memory copying now.
78055 *
78056 * Example structure (greedy, match maximum # atoms):
78057 *
78058 * SPLIT1 LSEQ
78059 * (atom)
78060 * SPLIT1 LSEQ ; <- the byte length of this instruction is needed
78061 * (atom) ; to encode the above SPLIT1 correctly
78062 * ...
78063 * LSEQ:
78064 */
78065 duk_uint32_t offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx);
78066 while (tmp_qmax > 0) {
78067 duk__insert_slice(re_ctx, offset, atom_start_offset, atom_code_length);
78068 if (re_ctx->curr_token.greedy) {
78069 duk__insert_u32(re_ctx, offset, DUK_REOP_SPLIT1); /* prefer direct */
78070 } else {
78071 duk__insert_u32(re_ctx, offset, DUK_REOP_SPLIT2); /* prefer jump */
78072 }
78073 duk__insert_jump_offset(re_ctx,
78074 offset + 1, /* +1 for opcode */
78075 (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - (offset + 1)));
78076 tmp_qmax--;
78077 }
78078 }
78079
78080 /* remove the original 'template' atom */
78081 duk__remove_slice(re_ctx, atom_start_offset, atom_code_length);
78082 }
78083
78084 /* 'taint' result as complex */
78085 res_charlen = -1;
78086 break;
78087 }
78088 case DUK_RETOK_ASSERT_START: {
78089 duk__append_u32(re_ctx, DUK_REOP_ASSERT_START);
78090 break;
78091 }
78092 case DUK_RETOK_ASSERT_END: {
78093 duk__append_u32(re_ctx, DUK_REOP_ASSERT_END);
78094 break;
78095 }
78096 case DUK_RETOK_ASSERT_WORD_BOUNDARY: {
78097 duk__append_u32(re_ctx, DUK_REOP_ASSERT_WORD_BOUNDARY);
78098 break;
78099 }
78100 case DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY: {
78101 duk__append_u32(re_ctx, DUK_REOP_ASSERT_NOT_WORD_BOUNDARY);
78102 break;
78103 }
78104 case DUK_RETOK_ASSERT_START_POS_LOOKAHEAD:
78105 case DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD: {
78106 duk_uint32_t offset;
78107 duk_uint32_t opcode = (re_ctx->curr_token.t == DUK_RETOK_ASSERT_START_POS_LOOKAHEAD) ?
78108 DUK_REOP_LOOKPOS : DUK_REOP_LOOKNEG;
78109
78110 offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx);
78111 duk__parse_disjunction(re_ctx, 0, &tmp_disj);
78112 duk__append_u32(re_ctx, DUK_REOP_MATCH);
78113
78114 (void) duk__insert_u32(re_ctx, offset, opcode);
78115 (void) duk__insert_jump_offset(re_ctx,
78116 offset + 1, /* +1 for opcode */
78117 (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - (offset + 1)));
78118
78119 /* 'taint' result as complex -- this is conservative,
78120 * as lookaheads do not backtrack.
78121 */
78122 res_charlen = -1;
78123 break;
78124 }
78125 case DUK_RETOK_ATOM_PERIOD: {
78126 new_atom_char_length = 1;
78127 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
78128 duk__append_u32(re_ctx, DUK_REOP_PERIOD);
78129 break;
78130 }
78131 case DUK_RETOK_ATOM_CHAR: {
78132 /* Note: successive characters could be joined into string matches
78133 * but this is not trivial (consider e.g. '/xyz+/); see docs for
78134 * more discussion.
78135 */
78136 duk_uint32_t ch;
78137
78138 new_atom_char_length = 1;
78139 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
78140 duk__append_u32(re_ctx, DUK_REOP_CHAR);
78141 ch = re_ctx->curr_token.num;
78142 if (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) {
78143 ch = duk_unicode_re_canonicalize_char(re_ctx->thr, ch);
78144 }
78145 duk__append_u32(re_ctx, ch);
78146 break;
78147 }
78148 case DUK_RETOK_ATOM_DIGIT:
78149 case DUK_RETOK_ATOM_NOT_DIGIT: {
78150 new_atom_char_length = 1;
78151 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
78152 duk__append_u32(re_ctx,
78153 (re_ctx->curr_token.t == DUK_RETOK_ATOM_DIGIT) ?
78154 DUK_REOP_RANGES : DUK_REOP_INVRANGES);
78155 duk__append_u32(re_ctx, sizeof(duk_unicode_re_ranges_digit) / (2 * sizeof(duk_uint16_t)));
78156 duk__append_u16_list(re_ctx, duk_unicode_re_ranges_digit, sizeof(duk_unicode_re_ranges_digit) / sizeof(duk_uint16_t));
78157 break;
78158 }
78159 case DUK_RETOK_ATOM_WHITE:
78160 case DUK_RETOK_ATOM_NOT_WHITE: {
78161 new_atom_char_length = 1;
78162 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
78163 duk__append_u32(re_ctx,
78164 (re_ctx->curr_token.t == DUK_RETOK_ATOM_WHITE) ?
78165 DUK_REOP_RANGES : DUK_REOP_INVRANGES);
78166 duk__append_u32(re_ctx, sizeof(duk_unicode_re_ranges_white) / (2 * sizeof(duk_uint16_t)));
78167 duk__append_u16_list(re_ctx, duk_unicode_re_ranges_white, sizeof(duk_unicode_re_ranges_white) / sizeof(duk_uint16_t));
78168 break;
78169 }
78170 case DUK_RETOK_ATOM_WORD_CHAR:
78171 case DUK_RETOK_ATOM_NOT_WORD_CHAR: {
78172 new_atom_char_length = 1;
78173 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
78174 duk__append_u32(re_ctx,
78175 (re_ctx->curr_token.t == DUK_RETOK_ATOM_WORD_CHAR) ?
78176 DUK_REOP_RANGES : DUK_REOP_INVRANGES);
78177 duk__append_u32(re_ctx, sizeof(duk_unicode_re_ranges_wordchar) / (2 * sizeof(duk_uint16_t)));
78178 duk__append_u16_list(re_ctx, duk_unicode_re_ranges_wordchar, sizeof(duk_unicode_re_ranges_wordchar) / sizeof(duk_uint16_t));
78179 break;
78180 }
78181 case DUK_RETOK_ATOM_BACKREFERENCE: {
78182 duk_uint32_t backref = (duk_uint32_t) re_ctx->curr_token.num;
78183 if (backref > re_ctx->highest_backref) {
78184 re_ctx->highest_backref = backref;
78185 }
78186 new_atom_char_length = -1; /* mark as complex */
78187 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
78188 duk__append_u32(re_ctx, DUK_REOP_BACKREFERENCE);
78189 duk__append_u32(re_ctx, backref);
78190 break;
78191 }
78192 case DUK_RETOK_ATOM_START_CAPTURE_GROUP: {
78193 duk_uint32_t cap;
78194
78195 new_atom_char_length = -1; /* mark as complex (capture handling) */
78196 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
78197 cap = ++re_ctx->captures;
78198 duk__append_u32(re_ctx, DUK_REOP_SAVE);
78199 duk__append_u32(re_ctx, cap * 2);
78200 duk__parse_disjunction(re_ctx, 0, &tmp_disj); /* retval (sub-atom char length) unused, tainted as complex above */
78201 duk__append_u32(re_ctx, DUK_REOP_SAVE);
78202 duk__append_u32(re_ctx, cap * 2 + 1);
78203 break;
78204 }
78205 case DUK_RETOK_ATOM_START_NONCAPTURE_GROUP: {
78206 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
78207 duk__parse_disjunction(re_ctx, 0, &tmp_disj);
78208 new_atom_char_length = tmp_disj.charlen;
78209 break;
78210 }
78211 case DUK_RETOK_ATOM_START_CHARCLASS:
78212 case DUK_RETOK_ATOM_START_CHARCLASS_INVERTED: {
78213 /*
78214 * Range parsing is done with a special lexer function which calls
78215 * us for every range parsed. This is different from how rest of
78216 * the parsing works, but avoids a heavy, arbitrary size intermediate
78217 * value type to hold the ranges.
78218 *
78219 * Another complication is the handling of character ranges when
78220 * case insensitive matching is used (see docs for discussion).
78221 * The range handler callback given to the lexer takes care of this
78222 * as well.
78223 *
78224 * Note that duplicate ranges are not eliminated when parsing character
78225 * classes, so that canonicalization of
78226 *
78227 * [0-9a-fA-Fx-{]
78228 *
78229 * creates the result (note the duplicate ranges):
78230 *
78231 * [0-9A-FA-FX-Z{-{]
78232 *
78233 * where [x-{] is split as a result of canonicalization. The duplicate
78234 * ranges are not a semantics issue: they work correctly.
78235 */
78236
78237 duk_uint32_t offset;
78238
78239 DUK_DD(DUK_DDPRINT("character class"));
78240
78241 /* insert ranges instruction, range count patched in later */
78242 new_atom_char_length = 1;
78243 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
78244 duk__append_u32(re_ctx,
78245 (re_ctx->curr_token.t == DUK_RETOK_ATOM_START_CHARCLASS) ?
78246 DUK_REOP_RANGES : DUK_REOP_INVRANGES);
78247 offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx); /* patch in range count later */
78248
78249 /* parse ranges until character class ends */
78250 re_ctx->nranges = 0; /* note: ctx-wide temporary */
78251 duk_lexer_parse_re_ranges(&re_ctx->lex, duk__generate_ranges, (void *) re_ctx);
78252
78253 /* insert range count */
78254 duk__insert_u32(re_ctx, offset, re_ctx->nranges);
78255 break;
78256 }
78257 case DUK_RETOK_ATOM_END_GROUP: {
78258 if (expect_eof) {
11fdf7f2 78259 DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_UNEXPECTED_CLOSING_PAREN);
7c673cae
FG
78260 }
78261 goto done;
78262 }
78263 case DUK_RETOK_EOF: {
78264 if (!expect_eof) {
11fdf7f2 78265 DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_UNEXPECTED_END_OF_PATTERN);
7c673cae
FG
78266 }
78267 goto done;
78268 }
78269 default: {
11fdf7f2 78270 DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_UNEXPECTED_REGEXP_TOKEN);
7c673cae
FG
78271 }
78272 }
78273
78274 /* a complex (new) atom taints the result */
78275 if (new_atom_start_offset >= 0) {
78276 if (new_atom_char_length < 0) {
78277 res_charlen = -1;
78278 } else if (res_charlen >= 0) {
78279 /* only advance if not tainted */
78280 res_charlen += new_atom_char_length;
78281 }
78282 }
78283
78284 /* record previous atom info in case next token is a quantifier */
78285 atom_start_offset = new_atom_start_offset;
78286 atom_char_length = new_atom_char_length;
78287 atom_start_captures = new_atom_start_captures;
78288 }
78289
78290 done:
78291
78292 /* finish up pending jump and split for last alternative */
78293 if (unpatched_disjunction_jump >= 0) {
78294 duk_uint32_t offset;
78295
78296 DUK_ASSERT(unpatched_disjunction_split >= 0);
78297 offset = unpatched_disjunction_jump;
78298 offset += duk__insert_jump_offset(re_ctx,
78299 offset,
78300 (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - offset));
78301 /* offset is now target of the pending split (right after jump) */
78302 duk__insert_jump_offset(re_ctx,
78303 unpatched_disjunction_split,
78304 offset - unpatched_disjunction_split);
78305 }
78306
78307#if 0
78308 out_atom_info->end_captures = re_ctx->captures;
78309#endif
78310 out_atom_info->charlen = res_charlen;
78311 DUK_DDD(DUK_DDDPRINT("parse disjunction finished: charlen=%ld",
78312 (long) out_atom_info->charlen));
78313
78314 re_ctx->recursion_depth--;
78315}
78316
78317/*
78318 * Flags parsing (see E5 Section 15.10.4.1).
78319 */
78320
78321DUK_LOCAL duk_uint32_t duk__parse_regexp_flags(duk_hthread *thr, duk_hstring *h) {
78322 const duk_uint8_t *p;
78323 const duk_uint8_t *p_end;
78324 duk_uint32_t flags = 0;
78325
78326 p = DUK_HSTRING_GET_DATA(h);
78327 p_end = p + DUK_HSTRING_GET_BYTELEN(h);
78328
78329 /* Note: can be safely scanned as bytes (undecoded) */
78330
78331 while (p < p_end) {
78332 duk_uint8_t c = *p++;
78333 switch ((int) c) {
78334 case (int) 'g': {
78335 if (flags & DUK_RE_FLAG_GLOBAL) {
78336 goto error;
78337 }
78338 flags |= DUK_RE_FLAG_GLOBAL;
78339 break;
78340 }
78341 case (int) 'i': {
78342 if (flags & DUK_RE_FLAG_IGNORE_CASE) {
78343 goto error;
78344 }
78345 flags |= DUK_RE_FLAG_IGNORE_CASE;
78346 break;
78347 }
78348 case (int) 'm': {
78349 if (flags & DUK_RE_FLAG_MULTILINE) {
78350 goto error;
78351 }
78352 flags |= DUK_RE_FLAG_MULTILINE;
78353 break;
78354 }
78355 default: {
78356 goto error;
78357 }
78358 }
78359 }
78360
78361 return flags;
78362
78363 error:
11fdf7f2 78364 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_REGEXP_FLAGS);
7c673cae
FG
78365 return 0; /* never here */
78366}
78367
78368/*
78369 * Create escaped RegExp source (E5 Section 15.10.3).
78370 *
78371 * The current approach is to special case the empty RegExp
78372 * ('' -> '(?:)') and otherwise replace unescaped '/' characters
78373 * with '\/' regardless of where they occur in the regexp.
78374 *
78375 * Note that normalization does not seem to be necessary for
78376 * RegExp literals (e.g. '/foo/') because to be acceptable as
78377 * a RegExp literal, the text between forward slashes must
78378 * already match the escaping requirements (e.g. must not contain
78379 * unescaped forward slashes or be empty). Escaping IS needed
78380 * for expressions like 'new Regexp("...", "")' however.
78381 * Currently, we re-escape in either case.
78382 *
78383 * Also note that we process the source here in UTF-8 encoded
78384 * form. This is correct, because any non-ASCII characters are
78385 * passed through without change.
78386 */
78387
78388DUK_LOCAL void duk__create_escaped_source(duk_hthread *thr, int idx_pattern) {
78389 duk_context *ctx = (duk_context *) thr;
78390 duk_hstring *h;
78391 const duk_uint8_t *p;
78392 duk_bufwriter_ctx bw_alloc;
78393 duk_bufwriter_ctx *bw;
78394 duk_uint8_t *q;
78395 duk_size_t i, n;
78396 duk_uint_fast8_t c_prev, c;
78397
78398 h = duk_get_hstring(ctx, idx_pattern);
78399 DUK_ASSERT(h != NULL);
78400 p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
78401 n = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h);
78402
78403 if (n == 0) {
78404 /* return '(?:)' */
78405 duk_push_hstring_stridx(ctx, DUK_STRIDX_ESCAPED_EMPTY_REGEXP);
78406 return;
78407 }
78408
78409 bw = &bw_alloc;
78410 DUK_BW_INIT_PUSHBUF(thr, bw, n);
78411 q = DUK_BW_GET_PTR(thr, bw);
78412
78413 c_prev = (duk_uint_fast8_t) 0;
78414
78415 for (i = 0; i < n; i++) {
78416 c = p[i];
78417
78418 q = DUK_BW_ENSURE_RAW(thr, bw, 2, q);
78419
78420 if (c == (duk_uint_fast8_t) '/' && c_prev != (duk_uint_fast8_t) '\\') {
78421 /* Unescaped '/' ANYWHERE in the regexp (in disjunction,
78422 * inside a character class, ...) => same escape works.
78423 */
78424 *q++ = DUK_ASC_BACKSLASH;
78425 }
78426 *q++ = (duk_uint8_t) c;
78427
78428 c_prev = c;
78429 }
78430
78431 DUK_BW_SETPTR_AND_COMPACT(thr, bw, q);
78432 duk_to_string(ctx, -1); /* -> [ ... escaped_source ] */
78433}
78434
78435/*
78436 * Exposed regexp compilation primitive.
78437 *
78438 * Sets up a regexp compilation context, and calls duk__parse_disjunction() to do the
78439 * actual parsing. Handles generation of the compiled regexp header and the
78440 * "boilerplate" capture of the matching substring (save 0 and 1). Also does some
78441 * global level regexp checks after recursive compilation has finished.
78442 *
78443 * An escaped version of the regexp source, suitable for use as a RegExp instance
78444 * 'source' property (see E5 Section 15.10.3), is also left on the stack.
78445 *
78446 * Input stack: [ pattern flags ]
78447 * Output stack: [ bytecode escaped_source ] (both as strings)
78448 */
78449
78450DUK_INTERNAL void duk_regexp_compile(duk_hthread *thr) {
78451 duk_context *ctx = (duk_context *) thr;
78452 duk_re_compiler_ctx re_ctx;
78453 duk_lexer_point lex_point;
78454 duk_hstring *h_pattern;
78455 duk_hstring *h_flags;
78456 duk__re_disjunction_info ign_disj;
78457
78458 DUK_ASSERT(thr != NULL);
78459 DUK_ASSERT(ctx != NULL);
78460
78461 /*
78462 * Args validation
78463 */
78464
78465 /* TypeError if fails */
78466 h_pattern = duk_require_hstring(ctx, -2);
78467 h_flags = duk_require_hstring(ctx, -1);
78468
78469 /*
78470 * Create normalized 'source' property (E5 Section 15.10.3).
78471 */
78472
78473 /* [ ... pattern flags ] */
78474
78475 duk__create_escaped_source(thr, -2);
78476
78477 /* [ ... pattern flags escaped_source ] */
78478
78479 /*
78480 * Init compilation context
78481 */
78482
78483 /* [ ... pattern flags escaped_source buffer ] */
78484
78485 DUK_MEMZERO(&re_ctx, sizeof(re_ctx));
78486 DUK_LEXER_INITCTX(&re_ctx.lex); /* duplicate zeroing, expect for (possible) NULL inits */
78487 re_ctx.thr = thr;
78488 re_ctx.lex.thr = thr;
78489 re_ctx.lex.input = DUK_HSTRING_GET_DATA(h_pattern);
78490 re_ctx.lex.input_length = DUK_HSTRING_GET_BYTELEN(h_pattern);
78491 re_ctx.lex.token_limit = DUK_RE_COMPILE_TOKEN_LIMIT;
78492 re_ctx.recursion_limit = DUK_USE_REGEXP_COMPILER_RECLIMIT;
78493 re_ctx.re_flags = duk__parse_regexp_flags(thr, h_flags);
78494
78495 DUK_BW_INIT_PUSHBUF(thr, &re_ctx.bw, DUK__RE_INITIAL_BUFSIZE);
78496
78497 DUK_DD(DUK_DDPRINT("regexp compiler ctx initialized, flags=0x%08lx, recursion_limit=%ld",
78498 (unsigned long) re_ctx.re_flags, (long) re_ctx.recursion_limit));
78499
78500 /*
78501 * Init lexer
78502 */
78503
78504 lex_point.offset = 0; /* expensive init, just want to fill window */
78505 lex_point.line = 1;
78506 DUK_LEXER_SETPOINT(&re_ctx.lex, &lex_point);
78507
78508 /*
78509 * Compilation
78510 */
78511
11fdf7f2 78512 DUK_DD(DUK_DDPRINT("starting regexp compilation"));
7c673cae
FG
78513
78514 duk__append_u32(&re_ctx, DUK_REOP_SAVE);
78515 duk__append_u32(&re_ctx, 0);
78516 duk__parse_disjunction(&re_ctx, 1 /*expect_eof*/, &ign_disj);
78517 duk__append_u32(&re_ctx, DUK_REOP_SAVE);
78518 duk__append_u32(&re_ctx, 1);
78519 duk__append_u32(&re_ctx, DUK_REOP_MATCH);
78520
78521 /*
78522 * Check for invalid backreferences; note that it is NOT an error
78523 * to back-reference a capture group which has not yet been introduced
78524 * in the pattern (as in /\1(foo)/); in fact, the backreference will
78525 * always match! It IS an error to back-reference a capture group
78526 * which will never be introduced in the pattern. Thus, we can check
78527 * for such references only after parsing is complete.
78528 */
78529
78530 if (re_ctx.highest_backref > re_ctx.captures) {
11fdf7f2 78531 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_BACKREFS);
7c673cae
FG
78532 }
78533
78534 /*
78535 * Emit compiled regexp header: flags, ncaptures
78536 * (insertion order inverted on purpose)
78537 */
78538
78539 duk__insert_u32(&re_ctx, 0, (re_ctx.captures + 1) * 2);
78540 duk__insert_u32(&re_ctx, 0, re_ctx.re_flags);
78541
78542 /* [ ... pattern flags escaped_source buffer ] */
78543
78544 DUK_BW_COMPACT(thr, &re_ctx.bw);
78545 duk_to_string(ctx, -1); /* coerce to string */
78546
78547 /* [ ... pattern flags escaped_source bytecode ] */
78548
78549 /*
78550 * Finalize stack
78551 */
78552
78553 duk_remove(ctx, -4); /* -> [ ... flags escaped_source bytecode ] */
78554 duk_remove(ctx, -3); /* -> [ ... escaped_source bytecode ] */
78555
11fdf7f2
TL
78556 DUK_DD(DUK_DDPRINT("regexp compilation successful, bytecode: %!T, escaped source: %!T",
78557 (duk_tval *) duk_get_tval(ctx, -1), (duk_tval *) duk_get_tval(ctx, -2)));
7c673cae
FG
78558}
78559
78560/*
78561 * Create a RegExp instance (E5 Section 15.10.7).
78562 *
78563 * Note: the output stack left by duk_regexp_compile() is directly compatible
78564 * with the input here.
78565 *
78566 * Input stack: [ escaped_source bytecode ] (both as strings)
78567 * Output stack: [ RegExp ]
78568 */
78569
78570DUK_INTERNAL void duk_regexp_create_instance(duk_hthread *thr) {
78571 duk_context *ctx = (duk_context *) thr;
78572 duk_hobject *h;
78573 duk_hstring *h_bc;
78574 duk_small_int_t re_flags;
78575
78576 /* [ ... escape_source bytecode ] */
78577
78578 h_bc = duk_get_hstring(ctx, -1);
78579 DUK_ASSERT(h_bc != NULL);
78580 DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(h_bc) >= 1); /* always at least the header */
78581 DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h_bc) >= 1);
78582 DUK_ASSERT((duk_small_int_t) DUK_HSTRING_GET_DATA(h_bc)[0] < 0x80); /* flags always encodes to 1 byte */
78583 re_flags = (duk_small_int_t) DUK_HSTRING_GET_DATA(h_bc)[0];
78584
78585 /* [ ... escaped_source bytecode ] */
78586
78587 duk_push_object(ctx);
78588 h = duk_get_hobject(ctx, -1);
78589 DUK_ASSERT(h != NULL);
78590 duk_insert(ctx, -3);
78591
78592 /* [ ... regexp_object escaped_source bytecode ] */
78593
78594 DUK_HOBJECT_SET_CLASS_NUMBER(h, DUK_HOBJECT_CLASS_REGEXP);
78595 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[DUK_BIDX_REGEXP_PROTOTYPE]);
78596
78597 duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_INT_BYTECODE, DUK_PROPDESC_FLAGS_NONE);
78598
78599 /* [ ... regexp_object escaped_source ] */
78600
78601 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_SOURCE, DUK_PROPDESC_FLAGS_NONE);
78602
78603 /* [ ... regexp_object ] */
78604
78605 duk_push_boolean(ctx, (re_flags & DUK_RE_FLAG_GLOBAL));
78606 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_GLOBAL, DUK_PROPDESC_FLAGS_NONE);
78607
78608 duk_push_boolean(ctx, (re_flags & DUK_RE_FLAG_IGNORE_CASE));
78609 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_IGNORE_CASE, DUK_PROPDESC_FLAGS_NONE);
78610
78611 duk_push_boolean(ctx, (re_flags & DUK_RE_FLAG_MULTILINE));
78612 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_MULTILINE, DUK_PROPDESC_FLAGS_NONE);
78613
78614 duk_push_int(ctx, 0);
78615 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LAST_INDEX, DUK_PROPDESC_FLAGS_W);
78616
78617 /* [ ... regexp_object ] */
78618}
78619
78620#undef DUK__RE_BUFLEN
78621
78622#else /* DUK_USE_REGEXP_SUPPORT */
78623
78624/* regexp support disabled */
78625
78626#endif /* DUK_USE_REGEXP_SUPPORT */
7c673cae
FG
78627/*
78628 * Regexp executor.
78629 *
78630 * Safety: the Ecmascript executor should prevent user from reading and
78631 * replacing regexp bytecode. Even so, the executor must validate all
78632 * memory accesses etc. When an invalid access is detected (e.g. a 'save'
78633 * opcode to invalid, unallocated index) it should fail with an internal
78634 * error but not cause a segmentation fault.
78635 *
78636 * Notes:
78637 *
78638 * - Backtrack counts are limited to unsigned 32 bits but should
78639 * technically be duk_size_t for strings longer than 4G chars.
78640 * This also requires a regexp bytecode change.
78641 */
78642
78643/* include removed: duk_internal.h */
78644
78645#ifdef DUK_USE_REGEXP_SUPPORT
78646
78647/*
78648 * Helpers for UTF-8 handling
78649 *
78650 * For bytecode readers the duk_uint32_t and duk_int32_t types are correct
78651 * because they're used for more than just codepoints.
78652 */
78653
78654DUK_LOCAL duk_uint32_t duk__bc_get_u32(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **pc) {
78655 return (duk_uint32_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, pc, re_ctx->bytecode, re_ctx->bytecode_end);
78656}
78657
78658DUK_LOCAL duk_int32_t duk__bc_get_i32(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **pc) {
78659 duk_uint32_t t;
78660
78661 /* signed integer encoding needed to work with UTF-8 */
78662 t = (duk_uint32_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, pc, re_ctx->bytecode, re_ctx->bytecode_end);
78663 if (t & 1) {
78664 return -((duk_int32_t) (t >> 1));
78665 } else {
78666 return (duk_int32_t) (t >> 1);
78667 }
78668}
78669
78670DUK_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) {
78671 const duk_uint8_t *p;
78672
78673 /* Note: allow backtracking from p == ptr_end */
78674 p = *ptr;
78675 if (p < ptr_start || p > ptr_end) {
78676 goto fail;
78677 }
78678
78679 while (count > 0) {
78680 for (;;) {
78681 p--;
78682 if (p < ptr_start) {
78683 goto fail;
78684 }
78685 if ((*p & 0xc0) != 0x80) {
78686 /* utf-8 continuation bytes have the form 10xx xxxx */
78687 break;
78688 }
78689 }
78690 count--;
78691 }
78692 *ptr = p;
78693 return p;
78694
78695 fail:
11fdf7f2 78696 DUK_ERROR_INTERNAL_DEFMSG(thr);
7c673cae
FG
78697 return NULL; /* never here */
78698}
78699
78700DUK_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) {
78701 const duk_uint8_t *p;
78702
78703 p = *ptr;
78704 if (p < ptr_start || p >= ptr_end) {
78705 goto fail;
78706 }
78707
78708 while (count > 0) {
78709 for (;;) {
78710 p++;
78711
78712 /* Note: if encoding ends by hitting end of input, we don't check that
78713 * the encoding is valid, we just assume it is.
78714 */
78715 if (p >= ptr_end || ((*p & 0xc0) != 0x80)) {
78716 /* utf-8 continuation bytes have the form 10xx xxxx */
78717 break;
78718 }
78719 }
78720 count--;
78721 }
78722
78723 *ptr = p;
78724 return p;
78725
78726 fail:
11fdf7f2 78727 DUK_ERROR_INTERNAL_DEFMSG(thr);
7c673cae
FG
78728 return NULL; /* never here */
78729}
78730
78731/*
78732 * Helpers for dealing with the input string
78733 */
78734
78735/* Get a (possibly canonicalized) input character from current sp. The input
78736 * itself is never modified, and captures always record non-canonicalized
78737 * characters even in case-insensitive matching.
78738 */
78739DUK_LOCAL duk_codepoint_t duk__inp_get_cp(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **sp) {
78740 duk_codepoint_t res = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, sp, re_ctx->input, re_ctx->input_end);
78741 if (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) {
78742 res = duk_unicode_re_canonicalize_char(re_ctx->thr, res);
78743 }
78744 return res;
78745}
78746
78747DUK_LOCAL const duk_uint8_t *duk__inp_backtrack(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **sp, duk_uint_fast32_t count) {
78748 return duk__utf8_backtrack(re_ctx->thr, sp, re_ctx->input, re_ctx->input_end, count);
78749}
78750
78751/* Backtrack utf-8 input and return a (possibly canonicalized) input character. */
78752DUK_LOCAL duk_codepoint_t duk__inp_get_prev_cp(duk_re_matcher_ctx *re_ctx, const duk_uint8_t *sp) {
78753 /* note: caller 'sp' is intentionally not updated here */
78754 (void) duk__inp_backtrack(re_ctx, &sp, (duk_uint_fast32_t) 1);
78755 return duk__inp_get_cp(re_ctx, &sp);
78756}
78757
78758/*
78759 * Regexp recursive matching function.
78760 *
78761 * Returns 'sp' on successful match (points to character after last matched one),
78762 * NULL otherwise.
78763 *
78764 * The C recursion depth limit check is only performed in this function, this
78765 * suffices because the function is present in all true recursion required by
78766 * regexp execution.
78767 */
78768
78769DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const duk_uint8_t *pc, const duk_uint8_t *sp) {
78770 if (re_ctx->recursion_depth >= re_ctx->recursion_limit) {
11fdf7f2 78771 DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_REGEXP_EXECUTOR_RECURSION_LIMIT);
7c673cae
FG
78772 }
78773 re_ctx->recursion_depth++;
78774
78775 for (;;) {
78776 duk_small_int_t op;
78777
78778 if (re_ctx->steps_count >= re_ctx->steps_limit) {
11fdf7f2 78779 DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_REGEXP_EXECUTOR_STEP_LIMIT);
7c673cae
FG
78780 }
78781 re_ctx->steps_count++;
78782
78783 op = (duk_small_int_t) duk__bc_get_u32(re_ctx, &pc);
78784
78785 DUK_DDD(DUK_DDDPRINT("match: rec=%ld, steps=%ld, pc (after op)=%ld, sp=%ld, op=%ld",
78786 (long) re_ctx->recursion_depth,
78787 (long) re_ctx->steps_count,
78788 (long) (pc - re_ctx->bytecode),
78789 (long) (sp - re_ctx->input),
78790 (long) op));
78791
78792 switch (op) {
78793 case DUK_REOP_MATCH: {
78794 goto match;
78795 }
78796 case DUK_REOP_CHAR: {
78797 /*
78798 * Byte-based matching would be possible for case-sensitive
78799 * matching but not for case-insensitive matching. So, we
78800 * match by decoding the input and bytecode character normally.
78801 *
78802 * Bytecode characters are assumed to be already canonicalized.
78803 * Input characters are canonicalized automatically by
78804 * duk__inp_get_cp() if necessary.
78805 *
78806 * There is no opcode for matching multiple characters. The
78807 * regexp compiler has trouble joining strings efficiently
78808 * during compilation. See doc/regexp.rst for more discussion.
78809 */
78810 duk_codepoint_t c1, c2;
78811
78812 c1 = (duk_codepoint_t) duk__bc_get_u32(re_ctx, &pc);
78813 DUK_ASSERT(!(re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) ||
78814 c1 == duk_unicode_re_canonicalize_char(re_ctx->thr, c1)); /* canonicalized by compiler */
78815 if (sp >= re_ctx->input_end) {
78816 goto fail;
78817 }
78818 c2 = duk__inp_get_cp(re_ctx, &sp);
78819 DUK_DDD(DUK_DDDPRINT("char match, c1=%ld, c2=%ld", (long) c1, (long) c2));
78820 if (c1 != c2) {
78821 goto fail;
78822 }
78823 break;
78824 }
78825 case DUK_REOP_PERIOD: {
78826 duk_codepoint_t c;
78827
78828 if (sp >= re_ctx->input_end) {
78829 goto fail;
78830 }
78831 c = duk__inp_get_cp(re_ctx, &sp);
78832 if (duk_unicode_is_line_terminator(c)) {
78833 /* E5 Sections 15.10.2.8, 7.3 */
78834 goto fail;
78835 }
78836 break;
78837 }
78838 case DUK_REOP_RANGES:
78839 case DUK_REOP_INVRANGES: {
78840 duk_uint32_t n;
78841 duk_codepoint_t c;
78842 duk_small_int_t match;
78843
78844 n = duk__bc_get_u32(re_ctx, &pc);
78845 if (sp >= re_ctx->input_end) {
78846 goto fail;
78847 }
78848 c = duk__inp_get_cp(re_ctx, &sp);
78849
78850 match = 0;
78851 while (n) {
78852 duk_codepoint_t r1, r2;
78853 r1 = (duk_codepoint_t) duk__bc_get_u32(re_ctx, &pc);
78854 r2 = (duk_codepoint_t) duk__bc_get_u32(re_ctx, &pc);
78855 DUK_DDD(DUK_DDDPRINT("matching ranges/invranges, n=%ld, r1=%ld, r2=%ld, c=%ld",
78856 (long) n, (long) r1, (long) r2, (long) c));
78857 if (c >= r1 && c <= r2) {
78858 /* Note: don't bail out early, we must read all the ranges from
78859 * bytecode. Another option is to skip them efficiently after
78860 * breaking out of here. Prefer smallest code.
78861 */
78862 match = 1;
78863 }
78864 n--;
78865 }
78866
78867 if (op == DUK_REOP_RANGES) {
78868 if (!match) {
78869 goto fail;
78870 }
78871 } else {
78872 DUK_ASSERT(op == DUK_REOP_INVRANGES);
78873 if (match) {
78874 goto fail;
78875 }
78876 }
78877 break;
78878 }
78879 case DUK_REOP_ASSERT_START: {
78880 duk_codepoint_t c;
78881
78882 if (sp <= re_ctx->input) {
78883 break;
78884 }
78885 if (!(re_ctx->re_flags & DUK_RE_FLAG_MULTILINE)) {
78886 goto fail;
78887 }
78888 c = duk__inp_get_prev_cp(re_ctx, sp);
78889 if (duk_unicode_is_line_terminator(c)) {
78890 /* E5 Sections 15.10.2.8, 7.3 */
78891 break;
78892 }
78893 goto fail;
78894 }
78895 case DUK_REOP_ASSERT_END: {
78896 duk_codepoint_t c;
78897 const duk_uint8_t *tmp_sp;
78898
78899 if (sp >= re_ctx->input_end) {
78900 break;
78901 }
78902 if (!(re_ctx->re_flags & DUK_RE_FLAG_MULTILINE)) {
78903 goto fail;
78904 }
78905 tmp_sp = sp;
78906 c = duk__inp_get_cp(re_ctx, &tmp_sp);
78907 if (duk_unicode_is_line_terminator(c)) {
78908 /* E5 Sections 15.10.2.8, 7.3 */
78909 break;
78910 }
78911 goto fail;
78912 }
78913 case DUK_REOP_ASSERT_WORD_BOUNDARY:
78914 case DUK_REOP_ASSERT_NOT_WORD_BOUNDARY: {
78915 /*
78916 * E5 Section 15.10.2.6. The previous and current character
78917 * should -not- be canonicalized as they are now. However,
78918 * canonicalization does not affect the result of IsWordChar()
78919 * (which depends on Unicode characters never canonicalizing
78920 * into ASCII characters) so this does not matter.
78921 */
78922 duk_small_int_t w1, w2;
78923
78924 if (sp <= re_ctx->input) {
78925 w1 = 0; /* not a wordchar */
78926 } else {
78927 duk_codepoint_t c;
78928 c = duk__inp_get_prev_cp(re_ctx, sp);
78929 w1 = duk_unicode_re_is_wordchar(c);
78930 }
78931 if (sp >= re_ctx->input_end) {
78932 w2 = 0; /* not a wordchar */
78933 } else {
78934 const duk_uint8_t *tmp_sp = sp; /* dummy so sp won't get updated */
78935 duk_codepoint_t c;
78936 c = duk__inp_get_cp(re_ctx, &tmp_sp);
78937 w2 = duk_unicode_re_is_wordchar(c);
78938 }
78939
78940 if (op == DUK_REOP_ASSERT_WORD_BOUNDARY) {
78941 if (w1 == w2) {
78942 goto fail;
78943 }
78944 } else {
78945 DUK_ASSERT(op == DUK_REOP_ASSERT_NOT_WORD_BOUNDARY);
78946 if (w1 != w2) {
78947 goto fail;
78948 }
78949 }
78950 break;
78951 }
78952 case DUK_REOP_JUMP: {
78953 duk_int32_t skip;
78954
78955 skip = duk__bc_get_i32(re_ctx, &pc);
78956 pc += skip;
78957 break;
78958 }
78959 case DUK_REOP_SPLIT1: {
78960 /* split1: prefer direct execution (no jump) */
78961 const duk_uint8_t *sub_sp;
78962 duk_int32_t skip;
78963
78964 skip = duk__bc_get_i32(re_ctx, &pc);
78965 sub_sp = duk__match_regexp(re_ctx, pc, sp);
78966 if (sub_sp) {
78967 sp = sub_sp;
78968 goto match;
78969 }
78970 pc += skip;
78971 break;
78972 }
78973 case DUK_REOP_SPLIT2: {
78974 /* split2: prefer jump execution (not direct) */
78975 const duk_uint8_t *sub_sp;
78976 duk_int32_t skip;
78977
78978 skip = duk__bc_get_i32(re_ctx, &pc);
78979 sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
78980 if (sub_sp) {
78981 sp = sub_sp;
78982 goto match;
78983 }
78984 break;
78985 }
78986 case DUK_REOP_SQMINIMAL: {
78987 duk_uint32_t q, qmin, qmax;
78988 duk_int32_t skip;
78989 const duk_uint8_t *sub_sp;
78990
78991 qmin = duk__bc_get_u32(re_ctx, &pc);
78992 qmax = duk__bc_get_u32(re_ctx, &pc);
78993 skip = duk__bc_get_i32(re_ctx, &pc);
78994 DUK_DDD(DUK_DDDPRINT("minimal quantifier, qmin=%lu, qmax=%lu, skip=%ld",
78995 (unsigned long) qmin, (unsigned long) qmax, (long) skip));
78996
78997 q = 0;
78998 while (q <= qmax) {
78999 if (q >= qmin) {
79000 sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
79001 if (sub_sp) {
79002 sp = sub_sp;
79003 goto match;
79004 }
79005 }
79006 sub_sp = duk__match_regexp(re_ctx, pc, sp);
79007 if (!sub_sp) {
79008 break;
79009 }
79010 sp = sub_sp;
79011 q++;
79012 }
79013 goto fail;
79014 }
79015 case DUK_REOP_SQGREEDY: {
79016 duk_uint32_t q, qmin, qmax, atomlen;
79017 duk_int32_t skip;
79018 const duk_uint8_t *sub_sp;
79019
79020 qmin = duk__bc_get_u32(re_ctx, &pc);
79021 qmax = duk__bc_get_u32(re_ctx, &pc);
79022 atomlen = duk__bc_get_u32(re_ctx, &pc);
79023 skip = duk__bc_get_i32(re_ctx, &pc);
79024 DUK_DDD(DUK_DDDPRINT("greedy quantifier, qmin=%lu, qmax=%lu, atomlen=%lu, skip=%ld",
79025 (unsigned long) qmin, (unsigned long) qmax, (unsigned long) atomlen, (long) skip));
79026
79027 q = 0;
79028 while (q < qmax) {
79029 sub_sp = duk__match_regexp(re_ctx, pc, sp);
79030 if (!sub_sp) {
79031 break;
79032 }
79033 sp = sub_sp;
79034 q++;
79035 }
79036 while (q >= qmin) {
79037 sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
79038 if (sub_sp) {
79039 sp = sub_sp;
79040 goto match;
79041 }
79042 if (q == qmin) {
79043 break;
79044 }
79045
79046 /* Note: if atom were to contain e.g. captures, we would need to
79047 * re-match the atom to get correct captures. Simply quantifiers
79048 * do not allow captures in their atom now, so this is not an issue.
79049 */
79050
79051 DUK_DDD(DUK_DDDPRINT("greedy quantifier, backtrack %ld characters (atomlen)",
79052 (long) atomlen));
79053 sp = duk__inp_backtrack(re_ctx, &sp, (duk_uint_fast32_t) atomlen);
79054 q--;
79055 }
79056 goto fail;
79057 }
79058 case DUK_REOP_SAVE: {
79059 duk_uint32_t idx;
79060 const duk_uint8_t *old;
79061 const duk_uint8_t *sub_sp;
79062
79063 idx = duk__bc_get_u32(re_ctx, &pc);
79064 if (idx >= re_ctx->nsaved) {
79065 /* idx is unsigned, < 0 check is not necessary */
79066 DUK_D(DUK_DPRINT("internal error, regexp save index insane: idx=%ld", (long) idx));
79067 goto internal_error;
79068 }
79069 old = re_ctx->saved[idx];
79070 re_ctx->saved[idx] = sp;
79071 sub_sp = duk__match_regexp(re_ctx, pc, sp);
79072 if (sub_sp) {
79073 sp = sub_sp;
79074 goto match;
79075 }
79076 re_ctx->saved[idx] = old;
79077 goto fail;
79078 }
79079 case DUK_REOP_WIPERANGE: {
79080 /* Wipe capture range and save old values for backtracking.
79081 *
79082 * XXX: this typically happens with a relatively small idx_count.
79083 * It might be useful to handle cases where the count is small
79084 * (say <= 8) by saving the values in stack instead. This would
79085 * reduce memory churn and improve performance, at the cost of a
79086 * slightly higher code footprint.
79087 */
79088 duk_uint32_t idx_start, idx_count;
79089#ifdef DUK_USE_EXPLICIT_NULL_INIT
79090 duk_uint32_t idx_end, idx;
79091#endif
79092 duk_uint8_t **range_save;
79093 const duk_uint8_t *sub_sp;
79094
79095 idx_start = duk__bc_get_u32(re_ctx, &pc);
79096 idx_count = duk__bc_get_u32(re_ctx, &pc);
79097 DUK_DDD(DUK_DDDPRINT("wipe saved range: start=%ld, count=%ld -> [%ld,%ld] (captures [%ld,%ld])",
79098 (long) idx_start, (long) idx_count,
79099 (long) idx_start, (long) (idx_start + idx_count - 1),
79100 (long) (idx_start / 2), (long) ((idx_start + idx_count - 1) / 2)));
79101 if (idx_start + idx_count > re_ctx->nsaved || idx_count == 0) {
79102 /* idx is unsigned, < 0 check is not necessary */
79103 DUK_D(DUK_DPRINT("internal error, regexp wipe indices insane: idx_start=%ld, idx_count=%ld",
79104 (long) idx_start, (long) idx_count));
79105 goto internal_error;
79106 }
79107 DUK_ASSERT(idx_count > 0);
79108
79109 duk_require_stack((duk_context *) re_ctx->thr, 1);
79110 range_save = (duk_uint8_t **) duk_push_fixed_buffer((duk_context *) re_ctx->thr,
79111 sizeof(duk_uint8_t *) * idx_count);
79112 DUK_ASSERT(range_save != NULL);
79113 DUK_MEMCPY(range_save, re_ctx->saved + idx_start, sizeof(duk_uint8_t *) * idx_count);
79114#ifdef DUK_USE_EXPLICIT_NULL_INIT
79115 idx_end = idx_start + idx_count;
79116 for (idx = idx_start; idx < idx_end; idx++) {
79117 re_ctx->saved[idx] = NULL;
79118 }
79119#else
79120 DUK_MEMZERO((void *) (re_ctx->saved + idx_start), sizeof(duk_uint8_t *) * idx_count);
79121#endif
79122
79123 sub_sp = duk__match_regexp(re_ctx, pc, sp);
79124 if (sub_sp) {
79125 /* match: keep wiped/resaved values */
79126 DUK_DDD(DUK_DDDPRINT("match: keep wiped/resaved values [%ld,%ld] (captures [%ld,%ld])",
79127 (long) idx_start, (long) (idx_start + idx_count - 1),
79128 (long) (idx_start / 2), (long) ((idx_start + idx_count - 1) / 2)));
79129 duk_pop((duk_context *) re_ctx->thr);
79130 sp = sub_sp;
79131 goto match;
79132 }
79133
79134 /* fail: restore saves */
79135 DUK_DDD(DUK_DDDPRINT("fail: restore wiped/resaved values [%ld,%ld] (captures [%ld,%ld])",
79136 (long) idx_start, (long) (idx_start + idx_count - 1),
79137 (long) (idx_start / 2), (long) ((idx_start + idx_count - 1) / 2)));
79138 DUK_MEMCPY((void *) (re_ctx->saved + idx_start),
79139 (const void *) range_save,
79140 sizeof(duk_uint8_t *) * idx_count);
79141 duk_pop((duk_context *) re_ctx->thr);
79142 goto fail;
79143 }
79144 case DUK_REOP_LOOKPOS:
79145 case DUK_REOP_LOOKNEG: {
79146 /*
79147 * Needs a save of multiple saved[] entries depending on what range
79148 * may be overwritten. Because the regexp parser does no such analysis,
79149 * we currently save the entire saved array here. Lookaheads are thus
79150 * a bit expensive. Note that the saved array is not needed for just
79151 * the lookahead sub-match, but for the matching of the entire sequel.
79152 *
79153 * The temporary save buffer is pushed on to the valstack to handle
79154 * errors correctly. Each lookahead causes a C recursion and pushes
79155 * more stuff on the value stack. If the C recursion limit is less
79156 * than the value stack spare, there is no need to check the stack.
79157 * We do so regardless, just in case.
79158 */
79159
79160 duk_int32_t skip;
79161 duk_uint8_t **full_save;
79162 const duk_uint8_t *sub_sp;
79163
79164 DUK_ASSERT(re_ctx->nsaved > 0);
79165
79166 duk_require_stack((duk_context *) re_ctx->thr, 1);
79167 full_save = (duk_uint8_t **) duk_push_fixed_buffer((duk_context *) re_ctx->thr,
79168 sizeof(duk_uint8_t *) * re_ctx->nsaved);
79169 DUK_ASSERT(full_save != NULL);
79170 DUK_MEMCPY(full_save, re_ctx->saved, sizeof(duk_uint8_t *) * re_ctx->nsaved);
79171
79172 skip = duk__bc_get_i32(re_ctx, &pc);
79173 sub_sp = duk__match_regexp(re_ctx, pc, sp);
79174 if (op == DUK_REOP_LOOKPOS) {
79175 if (!sub_sp) {
79176 goto lookahead_fail;
79177 }
79178 } else {
79179 if (sub_sp) {
79180 goto lookahead_fail;
79181 }
79182 }
79183 sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
79184 if (sub_sp) {
79185 /* match: keep saves */
79186 duk_pop((duk_context *) re_ctx->thr);
79187 sp = sub_sp;
79188 goto match;
79189 }
79190
79191 /* fall through */
79192
79193 lookahead_fail:
79194 /* fail: restore saves */
79195 DUK_MEMCPY((void *) re_ctx->saved,
79196 (const void *) full_save,
79197 sizeof(duk_uint8_t *) * re_ctx->nsaved);
79198 duk_pop((duk_context *) re_ctx->thr);
79199 goto fail;
79200 }
79201 case DUK_REOP_BACKREFERENCE: {
79202 /*
79203 * Byte matching for back-references would be OK in case-
79204 * sensitive matching. In case-insensitive matching we need
79205 * to canonicalize characters, so back-reference matching needs
79206 * to be done with codepoints instead. So, we just decode
79207 * everything normally here, too.
79208 *
79209 * Note: back-reference index which is 0 or higher than
79210 * NCapturingParens (= number of capturing parens in the
79211 * -entire- regexp) is a compile time error. However, a
79212 * backreference referring to a valid capture which has
79213 * not matched anything always succeeds! See E5 Section
79214 * 15.10.2.9, step 5, sub-step 3.
79215 */
79216 duk_uint32_t idx;
79217 const duk_uint8_t *p;
79218
79219 idx = duk__bc_get_u32(re_ctx, &pc);
79220 idx = idx << 1; /* backref n -> saved indices [n*2, n*2+1] */
79221 if (idx < 2 || idx + 1 >= re_ctx->nsaved) {
79222 /* regexp compiler should catch these */
79223 DUK_D(DUK_DPRINT("internal error, backreference index insane"));
79224 goto internal_error;
79225 }
79226 if (!re_ctx->saved[idx] || !re_ctx->saved[idx+1]) {
79227 /* capture is 'undefined', always matches! */
79228 DUK_DDD(DUK_DDDPRINT("backreference: saved[%ld,%ld] not complete, always match",
79229 (long) idx, (long) (idx + 1)));
79230 break;
79231 }
79232 DUK_DDD(DUK_DDDPRINT("backreference: match saved[%ld,%ld]", (long) idx, (long) (idx + 1)));
79233
79234 p = re_ctx->saved[idx];
79235 while (p < re_ctx->saved[idx+1]) {
79236 duk_codepoint_t c1, c2;
79237
79238 /* Note: not necessary to check p against re_ctx->input_end:
79239 * the memory access is checked by duk__inp_get_cp(), while
79240 * valid compiled regexps cannot write a saved[] entry
79241 * which points to outside the string.
79242 */
79243 if (sp >= re_ctx->input_end) {
79244 goto fail;
79245 }
79246 c1 = duk__inp_get_cp(re_ctx, &p);
79247 c2 = duk__inp_get_cp(re_ctx, &sp);
79248 if (c1 != c2) {
79249 goto fail;
79250 }
79251 }
79252 break;
79253 }
79254 default: {
79255 DUK_D(DUK_DPRINT("internal error, regexp opcode error: %ld", (long) op));
79256 goto internal_error;
79257 }
79258 }
79259 }
79260
79261 match:
79262 re_ctx->recursion_depth--;
79263 return sp;
79264
79265 fail:
79266 re_ctx->recursion_depth--;
79267 return NULL;
79268
79269 internal_error:
11fdf7f2 79270 DUK_ERROR_INTERNAL_DEFMSG(re_ctx->thr);
7c673cae
FG
79271 return NULL; /* never here */
79272}
79273
79274/*
79275 * Exposed matcher function which provides the semantics of RegExp.prototype.exec().
79276 *
79277 * RegExp.prototype.test() has the same semantics as exec() but does not return the
79278 * result object (which contains the matching string and capture groups). Currently
79279 * there is no separate test() helper, so a temporary result object is created and
79280 * discarded if test() is needed. This is intentional, to save code space.
79281 *
79282 * Input stack: [ ... re_obj input ]
79283 * Output stack: [ ... result ]
79284 */
79285
79286DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_global) {
79287 duk_context *ctx = (duk_context *) thr;
79288 duk_re_matcher_ctx re_ctx;
79289 duk_hobject *h_regexp;
79290 duk_hstring *h_bytecode;
79291 duk_hstring *h_input;
11fdf7f2 79292 duk_uint8_t *p_buf;
7c673cae
FG
79293 const duk_uint8_t *pc;
79294 const duk_uint8_t *sp;
79295 duk_small_int_t match = 0;
79296 duk_small_int_t global;
79297 duk_uint_fast32_t i;
79298 double d;
79299 duk_uint32_t char_offset;
79300
79301 DUK_ASSERT(thr != NULL);
79302 DUK_ASSERT(ctx != NULL);
79303
79304 DUK_DD(DUK_DDPRINT("regexp match: regexp=%!T, input=%!T",
79305 (duk_tval *) duk_get_tval(ctx, -2),
79306 (duk_tval *) duk_get_tval(ctx, -1)));
79307
79308 /*
79309 * Regexp instance check, bytecode check, input coercion.
79310 *
79311 * See E5 Section 15.10.6.
79312 */
79313
79314 /* TypeError if wrong; class check, see E5 Section 15.10.6 */
79315 h_regexp = duk_require_hobject_with_class(ctx, -2, DUK_HOBJECT_CLASS_REGEXP);
79316 DUK_ASSERT(h_regexp != NULL);
79317 DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_regexp) == DUK_HOBJECT_CLASS_REGEXP);
79318 DUK_UNREF(h_regexp);
79319
79320 duk_to_string(ctx, -1);
79321 h_input = duk_get_hstring(ctx, -1);
79322 DUK_ASSERT(h_input != NULL);
79323
79324 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_INT_BYTECODE); /* [ ... re_obj input ] -> [ ... re_obj input bc ] */
79325 h_bytecode = duk_require_hstring(ctx, -1); /* no regexp instance should exist without a non-configurable bytecode property */
79326 DUK_ASSERT(h_bytecode != NULL);
79327
79328 /*
79329 * Basic context initialization.
79330 *
79331 * Some init values are read from the bytecode header
79332 * whose format is (UTF-8 codepoints):
79333 *
79334 * uint flags
79335 * uint nsaved (even, 2n+2 where n = num captures)
79336 */
79337
79338 /* [ ... re_obj input bc ] */
79339
79340 DUK_MEMZERO(&re_ctx, sizeof(re_ctx));
79341
79342 re_ctx.thr = thr;
11fdf7f2 79343 re_ctx.input = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
7c673cae 79344 re_ctx.input_end = re_ctx.input + DUK_HSTRING_GET_BYTELEN(h_input);
11fdf7f2 79345 re_ctx.bytecode = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_bytecode);
7c673cae
FG
79346 re_ctx.bytecode_end = re_ctx.bytecode + DUK_HSTRING_GET_BYTELEN(h_bytecode);
79347 re_ctx.saved = NULL;
79348 re_ctx.recursion_limit = DUK_USE_REGEXP_EXECUTOR_RECLIMIT;
79349 re_ctx.steps_limit = DUK_RE_EXECUTE_STEPS_LIMIT;
79350
79351 /* read header */
79352 pc = re_ctx.bytecode;
79353 re_ctx.re_flags = duk__bc_get_u32(&re_ctx, &pc);
79354 re_ctx.nsaved = duk__bc_get_u32(&re_ctx, &pc);
79355 re_ctx.bytecode = pc;
79356
79357 DUK_ASSERT(DUK_RE_FLAG_GLOBAL < 0x10000UL); /* must fit into duk_small_int_t */
79358 global = (duk_small_int_t) (force_global | (re_ctx.re_flags & DUK_RE_FLAG_GLOBAL));
79359
79360 DUK_ASSERT(re_ctx.nsaved >= 2);
79361 DUK_ASSERT((re_ctx.nsaved % 2) == 0);
79362
11fdf7f2
TL
79363 p_buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, sizeof(duk_uint8_t *) * re_ctx.nsaved);
79364 DUK_UNREF(p_buf);
7c673cae
FG
79365 re_ctx.saved = (const duk_uint8_t **) duk_get_buffer(ctx, -1, NULL);
79366 DUK_ASSERT(re_ctx.saved != NULL);
79367
79368 /* [ ... re_obj input bc saved_buf ] */
79369
11fdf7f2 79370#if defined(DUK_USE_EXPLICIT_NULL_INIT)
7c673cae
FG
79371 for (i = 0; i < re_ctx.nsaved; i++) {
79372 re_ctx.saved[i] = (duk_uint8_t *) NULL;
79373 }
11fdf7f2
TL
79374#elif defined(DUK_USE_ZERO_BUFFER_DATA)
79375 /* buffer is automatically zeroed */
79376#else
79377 DUK_MEMZERO((void *) p_buf, sizeof(duk_uint8_t *) * re_ctx.nsaved);
7c673cae
FG
79378#endif
79379
79380 DUK_DDD(DUK_DDDPRINT("regexp ctx initialized, flags=0x%08lx, nsaved=%ld, recursion_limit=%ld, steps_limit=%ld",
79381 (unsigned long) re_ctx.re_flags, (long) re_ctx.nsaved, (long) re_ctx.recursion_limit,
79382 (long) re_ctx.steps_limit));
79383
79384 /*
79385 * Get starting character offset for match, and initialize 'sp' based on it.
79386 *
79387 * Note: lastIndex is non-configurable so it must be present (we check the
79388 * internal class of the object above, so we know it is). User code can set
79389 * its value to an arbitrary (garbage) value though; E5 requires that lastIndex
79390 * be coerced to a number before using. The code below works even if the
79391 * property is missing: the value will then be coerced to zero.
79392 *
79393 * Note: lastIndex may be outside Uint32 range even after ToInteger() coercion.
79394 * For instance, ToInteger(+Infinity) = +Infinity. We track the match offset
79395 * as an integer, but pre-check it to be inside the 32-bit range before the loop.
79396 * If not, the check in E5 Section 15.10.6.2, step 9.a applies.
79397 */
79398
79399 /* XXX: lastIndex handling produces a lot of asm */
79400
79401 /* [ ... re_obj input bc saved_buf ] */
79402
79403 duk_get_prop_stridx(ctx, -4, DUK_STRIDX_LAST_INDEX); /* -> [ ... re_obj input bc saved_buf lastIndex ] */
79404 (void) duk_to_int(ctx, -1); /* ToInteger(lastIndex) */
79405 d = duk_get_number(ctx, -1); /* integer, but may be +/- Infinite, +/- zero (not NaN, though) */
79406 duk_pop(ctx);
79407
79408 if (global) {
79409 if (d < 0.0 || d > (double) DUK_HSTRING_GET_CHARLEN(h_input)) {
79410 /* match fail */
79411 char_offset = 0; /* not really necessary */
79412 DUK_ASSERT(match == 0);
79413 goto match_over;
79414 }
79415 char_offset = (duk_uint32_t) d;
79416 } else {
79417 /* lastIndex must be ignored for non-global regexps, but get the
79418 * value for (theoretical) side effects. No side effects can
79419 * really occur, because lastIndex is a normal property and is
79420 * always non-configurable for RegExp instances.
79421 */
79422 char_offset = (duk_uint32_t) 0;
79423 }
79424
79425 sp = re_ctx.input + duk_heap_strcache_offset_char2byte(thr, h_input, char_offset);
79426
79427 /*
79428 * Match loop.
79429 *
79430 * Try matching at different offsets until match found or input exhausted.
79431 */
79432
79433 /* [ ... re_obj input bc saved_buf ] */
79434
79435 DUK_ASSERT(match == 0);
79436
79437 for (;;) {
79438 /* char offset in [0, h_input->clen] (both ends inclusive), checked before entry */
79439 DUK_ASSERT_DISABLE(char_offset >= 0);
79440 DUK_ASSERT(char_offset <= DUK_HSTRING_GET_CHARLEN(h_input));
79441
79442 /* Note: ctx.steps is intentionally not reset, it applies to the entire unanchored match */
79443 DUK_ASSERT(re_ctx.recursion_depth == 0);
79444
79445 DUK_DDD(DUK_DDDPRINT("attempt match at char offset %ld; %p [%p,%p]",
11fdf7f2
TL
79446 (long) char_offset, (const void *) sp,
79447 (const void *) re_ctx.input, (const void *) re_ctx.input_end));
7c673cae
FG
79448
79449 /*
79450 * Note:
79451 *
79452 * - duk__match_regexp() is required not to longjmp() in ordinary "non-match"
79453 * conditions; a longjmp() will terminate the entire matching process.
79454 *
79455 * - Clearing saved[] is not necessary because backtracking does it
79456 *
79457 * - Backtracking also rewinds ctx.recursion back to zero, unless an
79458 * internal/limit error occurs (which causes a longjmp())
79459 *
79460 * - If we supported anchored matches, we would break out here
79461 * unconditionally; however, Ecmascript regexps don't have anchored
79462 * matches. It might make sense to implement a fast bail-out if
79463 * the regexp begins with '^' and sp is not 0: currently we'll just
79464 * run through the entire input string, trivially failing the match
79465 * at every non-zero offset.
79466 */
79467
79468 if (duk__match_regexp(&re_ctx, re_ctx.bytecode, sp) != NULL) {
79469 DUK_DDD(DUK_DDDPRINT("match at offset %ld", (long) char_offset));
79470 match = 1;
79471 break;
79472 }
79473
79474 /* advance by one character (code point) and one char_offset */
79475 char_offset++;
79476 if (char_offset > DUK_HSTRING_GET_CHARLEN(h_input)) {
79477 /*
79478 * Note:
79479 *
79480 * - Intentionally attempt (empty) match at char_offset == k_input->clen
79481 *
79482 * - Negative char_offsets have been eliminated and char_offset is duk_uint32_t
79483 * -> no need or use for a negative check
79484 */
79485
79486 DUK_DDD(DUK_DDDPRINT("no match after trying all sp offsets"));
79487 break;
79488 }
79489
79490 /* avoid calling at end of input, will DUK_ERROR (above check suffices to avoid this) */
79491 (void) duk__utf8_advance(thr, &sp, re_ctx.input, re_ctx.input_end, (duk_uint_fast32_t) 1);
79492 }
79493
79494 match_over:
79495
79496 /*
79497 * Matching complete, create result array or return a 'null'. Update lastIndex
79498 * if necessary. See E5 Section 15.10.6.2.
79499 *
79500 * Because lastIndex is a character (not byte) offset, we need the character
79501 * length of the match which we conveniently get as a side effect of interning
79502 * the matching substring (0th index of result array).
79503 *
79504 * saved[0] start pointer (~ byte offset) of current match
79505 * saved[1] end pointer (~ byte offset) of current match (exclusive)
79506 * char_offset start character offset of current match (-> .index of result)
79507 * char_end_offset end character offset (computed below)
79508 */
79509
79510 /* [ ... re_obj input bc saved_buf ] */
79511
79512 if (match) {
79513#ifdef DUK_USE_ASSERTIONS
79514 duk_hobject *h_res;
79515#endif
79516 duk_uint32_t char_end_offset = 0;
79517
79518 DUK_DDD(DUK_DDDPRINT("regexp matches at char_offset %ld", (long) char_offset));
79519
79520 DUK_ASSERT(re_ctx.nsaved >= 2); /* must have start and end */
79521 DUK_ASSERT((re_ctx.nsaved % 2) == 0); /* and even number */
79522
79523 /* XXX: Array size is known before and (2 * re_ctx.nsaved) but not taken
79524 * advantage of now. The array is not compacted either, as regexp match
79525 * objects are usually short lived.
79526 */
79527
79528 duk_push_array(ctx);
79529
79530#ifdef DUK_USE_ASSERTIONS
79531 h_res = duk_require_hobject(ctx, -1);
79532 DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h_res));
79533 DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(h_res));
79534 DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_res) == DUK_HOBJECT_CLASS_ARRAY);
79535#endif
79536
79537 /* [ ... re_obj input bc saved_buf res_obj ] */
79538
79539 duk_push_u32(ctx, char_offset);
79540 duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_INDEX);
79541
79542 duk_dup(ctx, -4);
79543 duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_INPUT);
79544
79545 for (i = 0; i < re_ctx.nsaved; i += 2) {
79546 /* Captures which are undefined have NULL pointers and are returned
79547 * as 'undefined'. The same is done when saved[] pointers are insane
79548 * (this should, of course, never happen in practice).
79549 */
79550 if (re_ctx.saved[i] && re_ctx.saved[i+1] && re_ctx.saved[i+1] >= re_ctx.saved[i]) {
79551 duk_hstring *h_saved;
79552
79553 duk_push_lstring(ctx,
11fdf7f2 79554 (const char *) re_ctx.saved[i],
7c673cae
FG
79555 (duk_size_t) (re_ctx.saved[i+1] - re_ctx.saved[i]));
79556 h_saved = duk_get_hstring(ctx, -1);
79557 DUK_ASSERT(h_saved != NULL);
79558
79559 if (i == 0) {
79560 /* Assumes that saved[0] and saved[1] are always
79561 * set by regexp bytecode (if not, char_end_offset
79562 * will be zero). Also assumes clen reflects the
79563 * correct char length.
79564 */
79565 char_end_offset = char_offset + DUK_HSTRING_GET_CHARLEN(h_saved);
79566 }
79567 } else {
79568 duk_push_undefined(ctx);
79569 }
79570
79571 /* [ ... re_obj input bc saved_buf res_obj val ] */
79572 duk_put_prop_index(ctx, -2, i / 2);
79573 }
79574
79575 /* [ ... re_obj input bc saved_buf res_obj ] */
79576
79577 /* NB: 'length' property is automatically updated by the array setup loop */
79578
79579 if (global) {
79580 /* global regexp: lastIndex updated on match */
79581 duk_push_u32(ctx, char_end_offset);
79582 duk_put_prop_stridx(ctx, -6, DUK_STRIDX_LAST_INDEX);
79583 } else {
79584 /* non-global regexp: lastIndex never updated on match */
79585 ;
79586 }
79587 } else {
79588 /*
79589 * No match, E5 Section 15.10.6.2, step 9.a.i - 9.a.ii apply, regardless
79590 * of 'global' flag of the RegExp. In particular, if lastIndex is invalid
79591 * initially, it is reset to zero.
79592 */
79593
79594 DUK_DDD(DUK_DDDPRINT("regexp does not match"));
79595
79596 duk_push_null(ctx);
79597
79598 /* [ ... re_obj input bc saved_buf res_obj ] */
79599
79600 duk_push_int(ctx, 0);
79601 duk_put_prop_stridx(ctx, -6, DUK_STRIDX_LAST_INDEX);
79602 }
79603
79604 /* [ ... re_obj input bc saved_buf res_obj ] */
79605
79606 duk_insert(ctx, -5);
79607
79608 /* [ ... res_obj re_obj input bc saved_buf ] */
79609
79610 duk_pop_n(ctx, 4);
79611
79612 /* [ ... res_obj ] */
79613
79614 /* XXX: these last tricks are unnecessary if the function is made
79615 * a genuine native function.
79616 */
79617}
79618
79619DUK_INTERNAL void duk_regexp_match(duk_hthread *thr) {
79620 duk__regexp_match_helper(thr, 0 /*force_global*/);
79621}
79622
79623/* This variant is needed by String.prototype.split(); it needs to perform
79624 * global-style matching on a cloned RegExp which is potentially non-global.
79625 */
79626DUK_INTERNAL void duk_regexp_match_force_global(duk_hthread *thr) {
79627 duk__regexp_match_helper(thr, 1 /*force_global*/);
79628}
79629
79630#else /* DUK_USE_REGEXP_SUPPORT */
79631
79632/* regexp support disabled */
79633
79634#endif /* DUK_USE_REGEXP_SUPPORT */
7c673cae
FG
79635/*
79636 * Self tests to ensure execution environment is sane. Intended to catch
79637 * compiler/platform problems which cannot be detected at compile time.
79638 */
79639
79640/* include removed: duk_internal.h */
79641
79642#if defined(DUK_USE_SELF_TESTS)
79643
79644/*
79645 * Unions and structs for self tests
79646 */
79647
79648typedef union {
79649 double d;
79650 duk_uint8_t c[8];
79651} duk__test_double_union;
79652
79653#define DUK__DBLUNION_CMP_TRUE(a,b) do { \
11fdf7f2 79654 if (DUK_MEMCMP((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) != 0) { \
7c673cae
FG
79655 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double union compares false (expected true)"); \
79656 } \
79657 } while (0)
79658
79659#define DUK__DBLUNION_CMP_FALSE(a,b) do { \
11fdf7f2 79660 if (DUK_MEMCMP((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) == 0) { \
7c673cae
FG
79661 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double union compares true (expected false)"); \
79662 } \
79663 } while (0)
79664
79665typedef union {
79666 duk_uint32_t i;
79667 duk_uint8_t c[8];
79668} duk__test_u32_union;
79669
79670/*
79671 * Various sanity checks for typing
79672 */
79673
79674DUK_LOCAL void duk__selftest_types(void) {
79675 if (!(sizeof(duk_int8_t) == 1 &&
79676 sizeof(duk_uint8_t) == 1 &&
79677 sizeof(duk_int16_t) == 2 &&
79678 sizeof(duk_uint16_t) == 2 &&
79679 sizeof(duk_int32_t) == 4 &&
79680 sizeof(duk_uint32_t) == 4)) {
79681 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_(u)int{8,16,32}_t size");
79682 }
79683#if defined(DUK_USE_64BIT_OPS)
79684 if (!(sizeof(duk_int64_t) == 8 &&
79685 sizeof(duk_uint64_t) == 8)) {
79686 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_(u)int64_t size");
79687 }
79688#endif
79689
79690 if (!(sizeof(duk_size_t) >= sizeof(duk_uint_t))) {
79691 /* Some internal code now assumes that all duk_uint_t values
79692 * can be expressed with a duk_size_t.
79693 */
79694 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_size_t is smaller than duk_uint_t");
79695 }
79696 if (!(sizeof(duk_int_t) >= 4)) {
79697 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_int_t is not 32 bits");
79698 }
79699}
79700
79701/*
79702 * Packed tval sanity
79703 */
79704
79705DUK_LOCAL void duk__selftest_packed_tval(void) {
79706#if defined(DUK_USE_PACKED_TVAL)
79707 if (sizeof(void *) > 4) {
79708 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: packed duk_tval in use but sizeof(void *) > 4");
79709 }
79710#endif
79711}
79712
79713/*
79714 * Two's complement arithmetic.
79715 */
79716
79717DUK_LOCAL void duk__selftest_twos_complement(void) {
79718 volatile int test;
79719 test = -1;
11fdf7f2
TL
79720
79721 /* Note that byte order doesn't affect this test: all bytes in
79722 * 'test' will be 0xFF for two's complement.
79723 */
79724 if (((volatile duk_uint8_t *) &test)[0] != (duk_uint8_t) 0xff) {
7c673cae
FG
79725 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: two's complement arithmetic");
79726 }
79727}
79728
79729/*
79730 * Byte order. Important to self check, because on some exotic platforms
79731 * there is no actual detection but rather assumption based on platform
79732 * defines.
79733 */
79734
79735DUK_LOCAL void duk__selftest_byte_order(void) {
79736 duk__test_u32_union u1;
79737 duk__test_double_union u2;
79738
79739 /*
79740 * >>> struct.pack('>d', 102030405060).encode('hex')
79741 * '4237c17c6dc40000'
79742 */
79743#if defined(DUK_USE_INTEGER_LE)
79744 u1.c[0] = 0xef; u1.c[1] = 0xbe; u1.c[2] = 0xad; u1.c[3] = 0xde;
79745#elif defined(DUK_USE_INTEGER_ME)
79746#error integer mixed endian not supported now
79747#elif defined(DUK_USE_INTEGER_BE)
79748 u1.c[0] = 0xde; u1.c[1] = 0xad; u1.c[2] = 0xbe; u1.c[3] = 0xef;
79749#else
79750#error unknown integer endianness
79751#endif
79752
79753#if defined(DUK_USE_DOUBLE_LE)
79754 u2.c[0] = 0x00; u2.c[1] = 0x00; u2.c[2] = 0xc4; u2.c[3] = 0x6d;
79755 u2.c[4] = 0x7c; u2.c[5] = 0xc1; u2.c[6] = 0x37; u2.c[7] = 0x42;
79756#elif defined(DUK_USE_DOUBLE_ME)
79757 u2.c[0] = 0x7c; u2.c[1] = 0xc1; u2.c[2] = 0x37; u2.c[3] = 0x42;
79758 u2.c[4] = 0x00; u2.c[5] = 0x00; u2.c[6] = 0xc4; u2.c[7] = 0x6d;
79759#elif defined(DUK_USE_DOUBLE_BE)
79760 u2.c[0] = 0x42; u2.c[1] = 0x37; u2.c[2] = 0xc1; u2.c[3] = 0x7c;
79761 u2.c[4] = 0x6d; u2.c[5] = 0xc4; u2.c[6] = 0x00; u2.c[7] = 0x00;
79762#else
79763#error unknown double endianness
79764#endif
79765
79766 if (u1.i != (duk_uint32_t) 0xdeadbeefUL) {
79767 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_uint32_t byte order");
79768 }
79769
79770 if (u2.d != (double) 102030405060.0) {
79771 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double byte order");
79772 }
79773}
79774
79775/*
79776 * DUK_BSWAP macros
79777 */
79778
79779DUK_LOCAL void duk__selftest_bswap_macros(void) {
79780 duk_uint32_t x32;
79781 duk_uint16_t x16;
79782 duk_double_union du;
79783 duk_double_t du_diff;
79784
79785 x16 = 0xbeefUL;
79786 x16 = DUK_BSWAP16(x16);
79787 if (x16 != (duk_uint16_t) 0xefbeUL) {
79788 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: DUK_BSWAP16");
79789 }
79790
79791 x32 = 0xdeadbeefUL;
79792 x32 = DUK_BSWAP32(x32);
79793 if (x32 != (duk_uint32_t) 0xefbeaddeUL) {
79794 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: DUK_BSWAP32");
79795 }
79796
79797 /* >>> struct.unpack('>d', '4000112233445566'.decode('hex'))
79798 * (2.008366013071895,)
79799 */
79800
79801 du.uc[0] = 0x40; du.uc[1] = 0x00; du.uc[2] = 0x11; du.uc[3] = 0x22;
79802 du.uc[4] = 0x33; du.uc[5] = 0x44; du.uc[6] = 0x55; du.uc[7] = 0x66;
79803 DUK_DBLUNION_DOUBLE_NTOH(&du);
79804 du_diff = du.d - 2.008366013071895;
79805#if 0
79806 DUK_FPRINTF(DUK_STDERR, "du_diff: %lg\n", (double) du_diff);
79807#endif
79808 if (du_diff > 1e-15) {
79809 /* Allow very small lenience because some compilers won't parse
79810 * exact IEEE double constants (happened in matrix testing with
79811 * Linux gcc-4.8 -m32 at least).
79812 */
79813#if 0
79814 DUK_FPRINTF(DUK_STDERR, "Result of DUK_DBLUNION_DOUBLE_NTOH: %02x %02x %02x %02x %02x %02x %02x %02x\n",
79815 (unsigned int) du.uc[0], (unsigned int) du.uc[1],
79816 (unsigned int) du.uc[2], (unsigned int) du.uc[3],
79817 (unsigned int) du.uc[4], (unsigned int) du.uc[5],
79818 (unsigned int) du.uc[6], (unsigned int) du.uc[7]);
79819#endif
79820 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: DUK_DBLUNION_DOUBLE_NTOH");
79821 }
79822}
79823
79824/*
79825 * Basic double / byte union memory layout.
79826 */
79827
79828DUK_LOCAL void duk__selftest_double_union_size(void) {
79829 if (sizeof(duk__test_double_union) != 8) {
79830 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: invalid union size");
79831 }
79832}
79833
79834/*
79835 * Union aliasing, see misc/clang_aliasing.c.
79836 */
79837
79838DUK_LOCAL void duk__selftest_double_aliasing(void) {
79839 duk__test_double_union a, b;
79840
79841 /* This testcase fails when Emscripten-generated code runs on Firefox.
79842 * It's not an issue because the failure should only affect packed
79843 * duk_tval representation, which is not used with Emscripten.
79844 */
11fdf7f2
TL
79845#if !defined(DUK_USE_PACKED_TVAL)
79846 DUK_D(DUK_DPRINT("skip double aliasing self test when duk_tval is not packed"));
7c673cae
FG
79847 return;
79848#endif
79849
11fdf7f2 79850 /* Test signaling NaN and alias assignment in all endianness combinations.
7c673cae
FG
79851 */
79852
79853 /* little endian */
79854 a.c[0] = 0x11; a.c[1] = 0x22; a.c[2] = 0x33; a.c[3] = 0x44;
79855 a.c[4] = 0x00; a.c[5] = 0x00; a.c[6] = 0xf1; a.c[7] = 0xff;
79856 b = a;
79857 DUK__DBLUNION_CMP_TRUE(&a, &b);
79858
79859 /* big endian */
79860 a.c[0] = 0xff; a.c[1] = 0xf1; a.c[2] = 0x00; a.c[3] = 0x00;
79861 a.c[4] = 0x44; a.c[5] = 0x33; a.c[6] = 0x22; a.c[7] = 0x11;
79862 b = a;
79863 DUK__DBLUNION_CMP_TRUE(&a, &b);
79864
79865 /* mixed endian */
79866 a.c[0] = 0x00; a.c[1] = 0x00; a.c[2] = 0xf1; a.c[3] = 0xff;
79867 a.c[4] = 0x11; a.c[5] = 0x22; a.c[6] = 0x33; a.c[7] = 0x44;
79868 b = a;
79869 DUK__DBLUNION_CMP_TRUE(&a, &b);
79870}
79871
79872/*
79873 * Zero sign, see misc/tcc_zerosign2.c.
79874 */
79875
79876DUK_LOCAL void duk__selftest_double_zero_sign(void) {
11fdf7f2 79877 duk__test_double_union a, b;
7c673cae
FG
79878
79879 a.d = 0.0;
79880 b.d = -a.d;
79881 DUK__DBLUNION_CMP_FALSE(&a, &b);
79882}
79883
79884/*
79885 * Struct size/alignment if platform requires it
79886 *
79887 * There are some compiler specific struct padding pragmas etc in use, this
79888 * selftest ensures they're correctly detected and used.
79889 */
79890
79891DUK_LOCAL void duk__selftest_struct_align(void) {
79892#if (DUK_USE_ALIGN_BY == 4)
79893 if ((sizeof(duk_hbuffer_fixed) % 4) != 0) {
79894 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: sizeof(duk_hbuffer_fixed) not aligned to 4");
79895 }
79896#elif (DUK_USE_ALIGN_BY == 8)
79897 if ((sizeof(duk_hbuffer_fixed) % 8) != 0) {
79898 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: sizeof(duk_hbuffer_fixed) not aligned to 8");
79899 }
79900#elif (DUK_USE_ALIGN_BY == 1)
79901 /* no check */
79902#else
79903#error invalid DUK_USE_ALIGN_BY
79904#endif
79905}
79906
79907/*
79908 * 64-bit arithmetic
79909 *
79910 * There are some platforms/compilers where 64-bit types are available
79911 * but don't work correctly. Test for known cases.
79912 */
79913
79914DUK_LOCAL void duk__selftest_64bit_arithmetic(void) {
79915#if defined(DUK_USE_64BIT_OPS)
79916 volatile duk_int64_t i;
79917 volatile duk_double_t d;
79918
79919 /* Catch a double-to-int64 cast issue encountered in practice. */
79920 d = 2147483648.0;
79921 i = (duk_int64_t) d;
79922 if (i != 0x80000000LL) {
79923 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: casting 2147483648.0 to duk_int64_t failed");
79924 }
79925#else
79926 /* nop */
79927#endif
79928}
79929
79930/*
79931 * Casting
79932 */
79933
79934DUK_LOCAL void duk__selftest_cast_double_to_small_uint(void) {
79935 /*
79936 * https://github.com/svaarala/duktape/issues/127#issuecomment-77863473
79937 */
79938
79939 duk_double_t d1, d2;
79940 duk_small_uint_t u;
79941
79942 duk_double_t d1v, d2v;
79943 duk_small_uint_t uv;
79944
79945 /* Test without volatiles */
79946
79947 d1 = 1.0;
79948 u = (duk_small_uint_t) d1;
79949 d2 = (duk_double_t) u;
79950
79951 if (!(d1 == 1.0 && u == 1 && d2 == 1.0 && d1 == d2)) {
79952 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double to duk_small_uint_t cast failed");
79953 }
79954
79955 /* Same test with volatiles */
79956
79957 d1v = 1.0;
79958 uv = (duk_small_uint_t) d1v;
79959 d2v = (duk_double_t) uv;
79960
79961 if (!(d1v == 1.0 && uv == 1 && d2v == 1.0 && d1v == d2v)) {
79962 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double to duk_small_uint_t cast failed");
79963 }
79964}
79965
79966DUK_LOCAL void duk__selftest_cast_double_to_uint32(void) {
79967 /*
79968 * This test fails on an exotic ARM target; double-to-uint
79969 * cast is incorrectly clamped to -signed- int highest value.
79970 *
79971 * https://github.com/svaarala/duktape/issues/336
79972 */
79973
79974 duk_double_t dv;
79975 duk_uint32_t uv;
79976
79977 dv = 3735928559.0; /* 0xdeadbeef in decimal */
79978 uv = (duk_uint32_t) dv;
79979
79980 if (uv != 0xdeadbeefUL) {
79981 DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double to duk_uint32_t cast failed");
79982 }
79983}
79984
79985/*
79986 * Self test main
79987 */
79988
79989DUK_INTERNAL void duk_selftest_run_tests(void) {
79990 duk__selftest_types();
79991 duk__selftest_packed_tval();
79992 duk__selftest_twos_complement();
79993 duk__selftest_byte_order();
79994 duk__selftest_bswap_macros();
79995 duk__selftest_double_union_size();
79996 duk__selftest_double_aliasing();
79997 duk__selftest_double_zero_sign();
79998 duk__selftest_struct_align();
79999 duk__selftest_64bit_arithmetic();
80000 duk__selftest_cast_double_to_small_uint();
80001 duk__selftest_cast_double_to_uint32();
80002}
80003
80004#undef DUK__DBLUNION_CMP_TRUE
80005#undef DUK__DBLUNION_CMP_FALSE
80006
80007#endif /* DUK_USE_SELF_TESTS */
80008/* include removed: duk_internal.h */
7c673cae
FG
80009
80010#if defined(DUK_USE_FASTINT)
80011
80012/*
80013 * Manually optimized double-to-fastint downgrade check.
80014 *
80015 * This check has a large impact on performance, especially for fastint
80016 * slow paths, so must be changed carefully. The code should probably be
80017 * optimized for the case where the result does not fit into a fastint,
80018 * to minimize the penalty for "slow path code" dealing with fractions etc.
80019 *
80020 * At least on one tested soft float ARM platform double-to-int64 coercion
80021 * is very slow (and sometimes produces incorrect results, see self tests).
80022 * This algorithm combines a fastint compatibility check and extracting the
80023 * integer value from an IEEE double for setting the tagged fastint. For
80024 * other platforms a more naive approach might be better.
80025 *
80026 * See doc/fastint.rst for details.
80027 */
80028
80029DUK_INTERNAL DUK_ALWAYS_INLINE void duk_tval_set_number_chkfast(duk_tval *tv, duk_double_t x) {
80030 duk_double_union du;
80031 duk_int64_t i;
80032 duk_small_int_t expt;
80033 duk_small_int_t shift;
80034
80035 /* XXX: optimize for packed duk_tval directly? */
80036
80037 du.d = x;
80038 i = (duk_int64_t) DUK_DBLUNION_GET_INT64(&du);
80039 expt = (duk_small_int_t) ((i >> 52) & 0x07ff);
80040 shift = expt - 1023;
80041
80042 if (shift >= 0 && shift <= 46) { /* exponents 1023 to 1069 */
80043 duk_int64_t t;
80044
80045 if (((0x000fffffffffffffLL >> shift) & i) == 0) {
80046 t = i | 0x0010000000000000LL; /* implicit leading one */
80047 t = t & 0x001fffffffffffffLL;
80048 t = t >> (52 - shift);
80049 if (i < 0) {
80050 t = -t;
80051 }
80052 DUK_TVAL_SET_FASTINT(tv, t);
80053 return;
80054 }
80055 } else if (shift == -1023) { /* exponent 0 */
80056 if (i >= 0 && (i & 0x000fffffffffffffLL) == 0) {
80057 /* Note: reject negative zero. */
80058 DUK_TVAL_SET_FASTINT(tv, (duk_int64_t) 0);
80059 return;
80060 }
80061 } else if (shift == 47) { /* exponent 1070 */
80062 if (i < 0 && (i & 0x000fffffffffffffLL) == 0) {
80063 DUK_TVAL_SET_FASTINT(tv, (duk_int64_t) DUK_FASTINT_MIN);
80064 return;
80065 }
80066 }
80067
80068 DUK_TVAL_SET_DOUBLE(tv, x);
80069 return;
80070}
80071
80072/*
80073 * Manually optimized number-to-double conversion
80074 */
80075
80076#if defined(DUK_USE_FASTINT) && defined(DUK_USE_PACKED_TVAL)
80077DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_packed(duk_tval *tv) {
80078 duk_double_union du;
80079 duk_uint64_t t;
80080
80081 t = (duk_uint64_t) DUK_DBLUNION_GET_UINT64(tv);
80082 if ((t >> 48) != DUK_TAG_FASTINT) {
80083 return tv->d;
80084 } else if (t & 0x0000800000000000ULL) {
80085 t = (duk_uint64_t) (-((duk_int64_t) t)); /* avoid unary minus on unsigned */
80086 t = t & 0x0000ffffffffffffULL; /* negative */
80087 t |= 0xc330000000000000ULL;
80088 DUK_DBLUNION_SET_UINT64(&du, t);
80089 return du.d + 4503599627370496.0; /* 1 << 52 */
80090 } else if (t != 0) {
80091 t &= 0x0000ffffffffffffULL; /* positive */
80092 t |= 0x4330000000000000ULL;
80093 DUK_DBLUNION_SET_UINT64(&du, t);
80094 return du.d - 4503599627370496.0; /* 1 << 52 */
80095 } else {
80096 return 0.0; /* zero */
80097 }
80098}
80099#endif /* DUK_USE_FASTINT && DUK_USE_PACKED_TVAL */
80100
80101#if 0 /* unused */
80102#if defined(DUK_USE_FASTINT) && !defined(DUK_USE_PACKED_TVAL)
80103DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_unpacked(duk_tval *tv) {
80104 duk_double_union du;
80105 duk_uint64_t t;
80106
80107 DUK_ASSERT(tv->t == DUK__TAG_NUMBER || tv->t == DUK_TAG_FASTINT);
80108
80109 if (tv->t == DUK_TAG_FASTINT) {
80110 if (tv->v.fi >= 0) {
80111 t = 0x4330000000000000ULL | (duk_uint64_t) tv->v.fi;
80112 DUK_DBLUNION_SET_UINT64(&du, t);
80113 return du.d - 4503599627370496.0; /* 1 << 52 */
80114 } else {
80115 t = 0xc330000000000000ULL | (duk_uint64_t) (-tv->v.fi);
80116 DUK_DBLUNION_SET_UINT64(&du, t);
80117 return du.d + 4503599627370496.0; /* 1 << 52 */
80118 }
80119 } else {
80120 return tv->v.d;
80121 }
80122}
80123#endif /* DUK_USE_FASTINT && DUK_USE_PACKED_TVAL */
80124#endif /* 0 */
80125
80126#if defined(DUK_USE_FASTINT) && !defined(DUK_USE_PACKED_TVAL)
80127DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv) {
80128 duk_double_union du;
80129 duk_uint64_t t;
80130
80131 DUK_ASSERT(tv->t == DUK_TAG_FASTINT);
80132
80133 if (tv->v.fi >= 0) {
80134 t = 0x4330000000000000ULL | (duk_uint64_t) tv->v.fi;
80135 DUK_DBLUNION_SET_UINT64(&du, t);
80136 return du.d - 4503599627370496.0; /* 1 << 52 */
80137 } else {
80138 t = 0xc330000000000000ULL | (duk_uint64_t) (-tv->v.fi);
80139 DUK_DBLUNION_SET_UINT64(&du, t);
80140 return du.d + 4503599627370496.0; /* 1 << 52 */
80141 }
80142}
80143#endif /* DUK_USE_FASTINT && DUK_USE_PACKED_TVAL */
80144
80145#endif /* DUK_USE_FASTINT */
7c673cae
FG
80146/*
80147 * Unicode support tables automatically generated during build.
80148 */
80149
80150/* include removed: duk_internal.h */
80151
80152/*
80153 * Unicode tables containing ranges of Unicode characters in a
80154 * packed format. These tables are used to match non-ASCII
80155 * characters of complex productions by resorting to a linear
80156 * range-by-range comparison. This is very slow, but is expected
80157 * to be very rare in practical Ecmascript source code, and thus
80158 * compactness is most important.
80159 *
80160 * The tables are matched using uni_range_match() and the format
80161 * is described in src/extract_chars.py.
80162 */
80163
80164#ifdef DUK_USE_SOURCE_NONBMP
80165/* IdentifierStart production with ASCII excluded */
80166/* duk_unicode_ids_noa[] */
80167/*
80168 * Automatically generated by extract_chars.py, do not edit!
80169 */
80170
80171const duk_uint8_t duk_unicode_ids_noa[791] = {
80172249,176,176,80,111,7,47,15,47,254,11,197,191,0,72,2,15,115,66,19,57,2,34,2,
80173240,66,244,50,247,185,248,234,241,99,8,241,127,58,240,182,47,31,241,191,21,
8017418,245,50,15,1,24,27,35,15,2,2,240,239,15,244,156,15,10,241,26,21,6,240,
80175101,10,4,15,9,240,159,157,242,100,15,4,8,159,1,98,102,115,19,240,98,98,4,
8017652,15,2,14,18,47,0,31,5,85,19,240,98,98,18,18,31,17,50,15,5,47,2,130,34,
80177240,98,98,18,68,15,4,15,1,31,21,115,19,240,98,98,18,68,15,16,18,47,1,15,3,
801782,84,34,52,18,2,20,20,36,191,8,15,38,114,34,240,114,146,68,15,12,23,31,21,
80179114,34,240,114,146,68,15,18,2,31,1,31,4,114,34,241,147,15,2,15,3,31,10,86,
80180240,36,240,130,130,3,111,44,242,2,29,111,44,18,3,18,3,7,50,98,34,2,3,18,50,
8018126,3,66,15,7,31,20,15,49,114,241,79,13,79,101,241,191,6,15,2,85,52,4,24,37,
80182205,15,3,241,107,241,178,4,255,224,59,35,54,32,35,63,25,35,63,17,35,54,32,
8018335,62,47,41,35,63,51,241,127,0,240,47,69,223,254,21,227,240,18,240,166,243,
80184180,47,1,194,63,0,240,47,0,240,47,0,194,47,1,242,79,21,5,15,53,244,137,241,
80185146,6,243,107,240,223,37,240,227,76,241,207,7,111,42,240,122,242,95,68,15,
8018679,241,255,3,111,41,240,238,31,2,241,111,12,241,79,27,43,241,79,93,50,63,0,
80187251,15,50,255,224,8,53,63,22,53,55,32,32,32,47,15,63,37,38,32,66,38,67,53,
8018892,98,38,246,96,224,240,44,245,112,80,57,32,68,112,32,32,35,42,51,100,80,
80189240,63,25,255,233,107,241,242,241,242,247,87,63,3,241,107,242,106,15,2,240,
80190122,98,98,98,98,98,98,98,111,66,15,254,12,146,240,184,132,52,95,70,114,47,
8019174,35,111,25,79,78,240,63,11,242,127,0,255,224,244,255,240,0,138,143,60,
80192255,240,4,11,239,38,255,227,127,243,95,30,63,253,79,0,177,240,111,31,240,
8019347,9,159,64,241,152,63,87,51,33,240,9,244,39,34,35,47,7,240,255,36,240,15,
8019434,243,5,64,240,15,12,191,7,240,191,13,143,31,240,224,242,47,25,240,146,39,
80195240,111,7,64,111,32,32,65,52,48,32,240,162,241,85,53,53,166,38,248,63,19,
80196240,255,255,0,26,150,223,7,95,33,255,240,0,255,143,254,2,3,242,227,245,175,
8019724,109,70,2,146,194,66,2,18,18,245,207,19,255,224,93,240,79,48,63,38,241,
80198171,246,100,47,119,241,111,10,127,10,207,73,69,53,53,50,241,91,47,10,47,3,
8019933,46,61,241,79,107,243,127,37,255,223,13,79,33,242,31,15,240,63,11,242,
80200127,14,63,20,87,36,241,207,142,255,226,86,83,2,241,194,20,3,240,127,156,
80201240,107,240,175,184,15,1,50,34,240,191,30,240,223,117,242,107,240,107,240,
8020263,127,243,159,254,42,239,37,243,223,29,255,238,68,255,226,97,248,63,83,
80203255,234,145,255,227,33,255,240,2,44,95,254,18,191,255,0,52,187,31,255,0,18,
80204242,244,82,243,114,19,3,19,50,178,2,98,243,18,51,114,98,240,194,50,66,4,98,
80205255,224,70,63,9,47,9,47,15,47,9,47,15,47,9,47,15,47,9,47,15,47,9,39,255,
80206240,1,114,143,255,0,149,201,241,191,254,242,124,252,239,255,0,46,214,255,
80207225,16,0,
80208};
80209#else
80210/* IdentifierStart production with ASCII and non-BMP excluded */
80211/* duk_unicode_ids_noabmp[] */
80212/*
80213 * Automatically generated by extract_chars.py, do not edit!
80214 */
80215
80216const duk_uint8_t duk_unicode_ids_noabmp[611] = {
80217249,176,176,80,111,7,47,15,47,254,11,197,191,0,72,2,15,115,66,19,57,2,34,2,
80218240,66,244,50,247,185,248,234,241,99,8,241,127,58,240,182,47,31,241,191,21,
8021918,245,50,15,1,24,27,35,15,2,2,240,239,15,244,156,15,10,241,26,21,6,240,
80220101,10,4,15,9,240,159,157,242,100,15,4,8,159,1,98,102,115,19,240,98,98,4,
8022152,15,2,14,18,47,0,31,5,85,19,240,98,98,18,18,31,17,50,15,5,47,2,130,34,
80222240,98,98,18,68,15,4,15,1,31,21,115,19,240,98,98,18,68,15,16,18,47,1,15,3,
802232,84,34,52,18,2,20,20,36,191,8,15,38,114,34,240,114,146,68,15,12,23,31,21,
80224114,34,240,114,146,68,15,18,2,31,1,31,4,114,34,241,147,15,2,15,3,31,10,86,
80225240,36,240,130,130,3,111,44,242,2,29,111,44,18,3,18,3,7,50,98,34,2,3,18,50,
8022626,3,66,15,7,31,20,15,49,114,241,79,13,79,101,241,191,6,15,2,85,52,4,24,37,
80227205,15,3,241,107,241,178,4,255,224,59,35,54,32,35,63,25,35,63,17,35,54,32,
8022835,62,47,41,35,63,51,241,127,0,240,47,69,223,254,21,227,240,18,240,166,243,
80229180,47,1,194,63,0,240,47,0,240,47,0,194,47,1,242,79,21,5,15,53,244,137,241,
80230146,6,243,107,240,223,37,240,227,76,241,207,7,111,42,240,122,242,95,68,15,
8023179,241,255,3,111,41,240,238,31,2,241,111,12,241,79,27,43,241,79,93,50,63,0,
80232251,15,50,255,224,8,53,63,22,53,55,32,32,32,47,15,63,37,38,32,66,38,67,53,
8023392,98,38,246,96,224,240,44,245,112,80,57,32,68,112,32,32,35,42,51,100,80,
80234240,63,25,255,233,107,241,242,241,242,247,87,63,3,241,107,242,106,15,2,240,
80235122,98,98,98,98,98,98,98,111,66,15,254,12,146,240,184,132,52,95,70,114,47,
8023674,35,111,25,79,78,240,63,11,242,127,0,255,224,244,255,240,0,138,143,60,
80237255,240,4,11,239,38,255,227,127,243,95,30,63,253,79,0,177,240,111,31,240,
8023847,9,159,64,241,152,63,87,51,33,240,9,244,39,34,35,47,7,240,255,36,240,15,
8023934,243,5,64,240,15,12,191,7,240,191,13,143,31,240,224,242,47,25,240,146,39,
80240240,111,7,64,111,32,32,65,52,48,32,240,162,241,85,53,53,166,38,248,63,19,
80241240,255,255,0,26,150,223,7,95,33,255,240,0,255,143,254,2,3,242,227,245,175,
8024224,109,70,2,146,194,66,2,18,18,245,207,19,255,224,93,240,79,48,63,38,241,
80243171,246,100,47,119,241,111,10,127,10,207,73,69,53,53,50,0,
80244};
80245#endif
80246
80247#ifdef DUK_USE_SOURCE_NONBMP
80248/* IdentifierStart production with Letter and ASCII excluded */
80249/* duk_unicode_ids_m_let_noa[] */
80250/*
80251 * Automatically generated by extract_chars.py, do not edit!
80252 */
80253
80254const duk_uint8_t duk_unicode_ids_m_let_noa[42] = {
80255255,240,0,94,18,255,233,99,241,51,63,254,215,32,240,184,240,2,255,240,6,89,
80256249,255,240,4,148,79,37,255,224,192,9,15,120,79,255,0,15,30,245,48,
80257};
80258#else
80259/* IdentifierStart production with Letter, ASCII, and non-BMP excluded */
80260/* duk_unicode_ids_m_let_noabmp[] */
80261/*
80262 * Automatically generated by extract_chars.py, do not edit!
80263 */
80264
80265const duk_uint8_t duk_unicode_ids_m_let_noabmp[24] = {
80266255,240,0,94,18,255,233,99,241,51,63,254,215,32,240,184,240,2,255,240,6,89,
80267249,0,
80268};
80269#endif
80270
80271#ifdef DUK_USE_SOURCE_NONBMP
80272/* IdentifierPart production with IdentifierStart and ASCII excluded */
80273/* duk_unicode_idp_m_ids_noa[] */
80274/*
80275 * Automatically generated by extract_chars.py, do not edit!
80276 */
80277
80278const duk_uint8_t duk_unicode_idp_m_ids_noa[397] = {
80279255,225,243,246,15,254,0,116,255,191,29,32,33,33,32,243,170,242,47,15,112,
80280245,118,53,49,35,57,240,144,241,15,11,244,218,240,25,241,56,241,67,40,34,
8028136,241,210,249,99,242,130,47,2,38,177,57,240,50,242,160,38,49,50,160,177,
8028257,240,50,242,160,36,81,50,64,240,107,64,194,242,160,39,34,34,240,97,57,
80283240,50,242,160,38,49,50,145,177,57,240,64,242,212,66,35,160,240,9,240,50,
80284242,198,34,35,129,193,57,240,65,242,160,38,34,35,129,193,57,240,65,242,198,
8028534,35,160,177,57,240,65,243,128,85,32,39,240,65,242,240,54,215,41,244,144,
8028653,33,197,57,243,1,121,192,32,32,81,242,63,4,33,106,47,20,160,245,111,4,41,
80287211,82,34,54,67,235,46,255,225,179,47,254,42,98,240,242,240,241,241,1,243,
8028879,14,160,57,241,50,57,248,16,246,139,91,185,245,47,1,129,121,242,244,242,
80289185,47,13,58,121,245,132,242,31,1,201,240,56,210,241,9,105,241,237,242,47,
802904,153,121,246,130,47,5,80,80,251,255,23,240,115,255,225,0,31,35,31,5,15,
80291109,197,4,191,254,175,34,247,240,245,47,16,255,225,30,95,91,31,255,0,100,
80292121,159,55,13,31,100,31,254,0,64,64,80,240,148,244,161,242,79,1,201,127,2,
80293240,9,240,231,240,188,241,227,242,29,240,25,244,29,208,145,57,241,48,242,
8029496,34,49,97,32,255,224,21,114,19,159,255,0,62,24,15,254,29,95,0,240,38,209,
80295240,162,251,41,241,112,255,225,177,15,254,25,105,255,228,75,34,22,63,26,37,
8029615,254,75,66,242,126,241,25,240,34,241,250,255,240,10,249,228,69,151,54,
80297241,3,248,98,255,228,125,242,47,255,12,23,244,254,0,
80298};
80299#else
80300/* IdentifierPart production with IdentifierStart, ASCII, and non-BMP excluded */
80301/* duk_unicode_idp_m_ids_noabmp[] */
80302/*
80303 * Automatically generated by extract_chars.py, do not edit!
80304 */
80305
80306const duk_uint8_t duk_unicode_idp_m_ids_noabmp[348] = {
80307255,225,243,246,15,254,0,116,255,191,29,32,33,33,32,243,170,242,47,15,112,
80308245,118,53,49,35,57,240,144,241,15,11,244,218,240,25,241,56,241,67,40,34,
8030936,241,210,249,99,242,130,47,2,38,177,57,240,50,242,160,38,49,50,160,177,
8031057,240,50,242,160,36,81,50,64,240,107,64,194,242,160,39,34,34,240,97,57,
80311240,50,242,160,38,49,50,145,177,57,240,64,242,212,66,35,160,240,9,240,50,
80312242,198,34,35,129,193,57,240,65,242,160,38,34,35,129,193,57,240,65,242,198,
8031334,35,160,177,57,240,65,243,128,85,32,39,240,65,242,240,54,215,41,244,144,
8031453,33,197,57,243,1,121,192,32,32,81,242,63,4,33,106,47,20,160,245,111,4,41,
80315211,82,34,54,67,235,46,255,225,179,47,254,42,98,240,242,240,241,241,1,243,
8031679,14,160,57,241,50,57,248,16,246,139,91,185,245,47,1,129,121,242,244,242,
80317185,47,13,58,121,245,132,242,31,1,201,240,56,210,241,9,105,241,237,242,47,
803184,153,121,246,130,47,5,80,80,251,255,23,240,115,255,225,0,31,35,31,5,15,
80319109,197,4,191,254,175,34,247,240,245,47,16,255,225,30,95,91,31,255,0,100,
80320121,159,55,13,31,100,31,254,0,64,64,80,240,148,244,161,242,79,1,201,127,2,
80321240,9,240,231,240,188,241,227,242,29,240,25,244,29,208,145,57,241,48,242,
8032296,34,49,97,32,255,224,21,114,19,159,255,0,62,24,15,254,29,95,0,240,38,209,
80323240,162,251,41,241,112,0,
80324};
80325#endif
80326
80327/*
80328 * Case conversion tables generated using src/extract_caseconv.py.
80329 */
80330
80331/* duk_unicode_caseconv_uc[] */
80332/* duk_unicode_caseconv_lc[] */
80333
80334/*
80335 * Automatically generated by extract_caseconv.py, do not edit!
80336 */
80337
80338const duk_uint8_t duk_unicode_caseconv_uc[1288] = {
80339132,3,128,3,0,184,7,192,6,192,112,35,242,199,224,64,74,192,49,32,128,162,
80340128,108,65,1,189,129,254,131,3,173,3,136,6,7,98,7,34,68,15,12,14,140,72,30,
80341104,28,112,32,67,0,65,4,0,138,0,128,4,1,88,65,76,83,15,128,15,132,8,31,16,
8034231,24,12,62,64,62,80,32,124,192,124,224,64,250,0,250,64,97,246,1,246,129,3,
80343238,3,247,64,135,220,135,242,2,15,187,15,237,2,31,120,31,248,4,62,244,63,
80344212,8,125,240,127,232,16,253,128,253,192,33,253,1,253,128,67,252,3,253,0,
80345136,92,8,88,8,18,104,18,91,26,44,48,44,0,94,90,0,33,64,155,253,7,252,132,
80346212,0,32,32,32,6,0,76,192,76,129,128,157,0,156,136,1,75,1,74,46,2,244,2,
80347242,12,6,12,6,8,16,13,8,13,0,48,27,64,27,48,64,57,192,57,162,0,119,192,119,
80348132,128,252,128,252,20,2,35,2,34,18,4,142,4,140,20,13,196,13,192,16,30,200,
8034930,192,192,70,16,70,2,32,145,96,145,70,193,48,129,48,67,130,104,130,104,44,
8035030,1,30,0,150,61,66,61,64,192,125,68,125,100,33,99,65,99,56,50,200,18,200,
803516,69,157,133,157,96,169,144,105,144,11,211,64,211,64,12,167,35,167,34,15,
8035278,103,78,100,126,157,234,157,228,21,59,253,59,240,90,122,26,122,0,163,128,
80353214,128,214,2,1,197,1,196,6,3,140,3,136,12,7,200,7,196,16,20,0,13,48,32,63,
80354128,63,112,69,142,101,142,64,130,1,136,1,135,4,3,114,3,112,8,26,120,202,
80355120,176,65,1,30,1,29,130,2,105,1,150,5,255,96,22,160,115,128,31,224,47,0,
8035638,32,9,32,47,224,10,96,48,0,72,96,50,64,50,32,50,160,62,192,51,32,51,0,51,
8035764,71,160,51,192,68,0,53,0,52,224,55,224,62,224,59,160,49,192,62,96,62,32,
8035874,5,141,224,74,37,141,160,74,69,142,0,74,96,48,32,74,128,48,192,75,32,49,
80359224,75,96,50,0,76,0,50,96,76,96,50,128,76,180,241,160,77,0,50,224,77,101,
80360140,64,78,37,141,192,78,64,51,160,78,160,51,224,79,165,140,128,81,0,53,192,
8036181,32,72,128,81,128,72,160,82,64,54,224,104,160,115,32,110,224,110,192,117,
80362128,112,192,120,64,116,96,121,128,113,128,122,0,114,64,122,32,115,0,122,
80363160,116,192,122,192,116,0,122,224,121,224,126,0,115,64,126,32,116,32,126,
8036464,127,32,126,160,114,160,153,224,152,3,175,52,239,163,175,165,140,99,211,
8036599,204,3,247,192,115,35,252,163,253,132,41,196,38,68,48,132,48,101,140,37,
80366140,5,140,160,71,69,140,192,71,217,128,55,224,5,48,5,48,20,152,10,240,1,56,
803677,194,0,74,3,12,3,144,192,230,64,194,0,192,64,236,48,58,80,48,128,48,16,88,
80368120,20,212,21,72,122,90,0,72,3,49,30,151,128,21,0,194,7,166,32,5,112,48,
80369161,233,152,1,100,12,40,122,106,0,65,2,190,31,80,128,233,64,196,199,212,
80370176,58,80,49,48,48,1,245,76,14,148,12,76,12,4,125,91,3,165,3,19,3,66,31,
80371128,135,194,0,230,71,224,97,240,144,57,145,248,40,124,40,14,100,126,14,31,
8037211,3,153,31,132,135,195,0,230,71,225,97,240,208,57,145,248,104,124,56,14,
80373100,126,30,31,15,3,153,31,136,135,194,0,230,71,226,97,240,144,57,145,248,
80374168,124,40,14,100,126,46,31,11,3,153,31,140,135,195,0,230,71,227,97,240,
80375208,57,145,248,232,124,56,14,100,126,62,31,15,3,153,31,144,135,202,0,230,
8037671,228,97,242,144,57,145,249,40,124,168,14,100,126,78,31,43,3,153,31,148,
80377135,203,0,230,71,229,97,242,208,57,145,249,104,124,184,14,100,126,94,31,47,
803783,153,31,152,135,202,0,230,71,230,97,242,144,57,145,249,168,124,168,14,100,
80379126,110,31,43,3,153,31,156,135,203,0,230,71,231,97,242,208,57,145,249,232,
80380124,184,14,100,126,126,31,47,3,153,31,160,135,218,0,230,71,232,97,246,144,
8038157,145,250,40,125,168,14,100,126,142,31,107,3,153,31,164,135,219,0,230,71,
80382233,97,246,208,57,145,250,104,125,184,14,100,126,158,31,111,3,153,31,168,
80383135,218,0,230,71,234,97,246,144,57,145,250,168,125,168,14,100,126,174,31,
80384107,3,153,31,172,135,219,0,230,71,235,97,246,208,57,145,250,232,125,184,14,
80385100,126,190,31,111,3,153,31,178,135,238,128,230,71,236,224,57,16,57,145,
80386251,72,14,24,14,100,126,218,3,145,3,66,31,183,192,228,64,208,128,230,71,
80387239,32,57,16,57,145,252,40,127,40,14,100,127,14,3,151,3,153,31,196,128,226,
8038864,230,71,241,160,57,112,52,33,252,124,14,92,13,8,14,100,127,50,3,151,3,
80389153,31,210,192,230,64,194,0,192,7,244,240,57,144,48,128,48,17,253,104,14,
80390100,13,8,127,95,3,153,3,8,3,66,31,226,192,233,64,194,0,192,7,248,240,58,80,
8039148,128,48,17,254,72,14,132,12,76,127,154,3,165,3,66,31,231,192,233,64,194,
803920,208,135,252,161,255,160,57,145,255,56,14,164,14,100,127,210,3,143,3,153,
8039331,246,128,234,64,208,135,253,240,58,144,52,32,57,145,255,200,14,164,14,
80394103,236,2,0,70,0,70,251,1,128,17,128,18,126,192,160,4,96,4,207,176,60,1,24,
803951,24,1,39,236,19,0,70,0,70,0,76,251,5,128,20,192,21,62,193,160,5,48,5,79,
80396177,56,21,16,21,27,236,82,5,68,5,53,251,21,129,81,1,78,254,197,160,84,224,
8039784,111,177,120,21,16,20,244,
80398};
80399const duk_uint8_t duk_unicode_caseconv_lc[616] = {
80400144,3,0,3,128,184,6,192,7,192,112,24,144,37,96,64,54,32,81,64,128,226,0,
80401235,65,129,199,1,230,130,3,145,3,177,34,7,70,7,134,36,15,244,13,236,24,32,
804020,34,129,0,65,0,67,4,0,166,32,172,41,132,40,11,64,19,15,132,15,128,8,31,24,
8040331,16,12,62,80,62,64,32,124,224,124,192,64,250,64,250,0,97,246,129,246,1,3,
80404241,3,240,2,7,230,7,228,4,15,212,15,208,8,31,184,31,176,4,63,116,62,224,8,
80405127,32,125,200,32,254,192,254,128,33,253,161,247,96,67,253,3,252,0,135,250,
80406135,222,129,15,252,15,188,2,31,250,31,124,4,66,192,66,224,64,146,216,147,
8040764,209,96,1,97,130,242,199,224,35,240,95,228,63,232,38,161,1,0,1,1,48,2,
80408100,2,102,12,4,228,4,232,64,10,80,10,89,112,23,144,23,160,96,48,64,48,96,
80409128,104,0,104,65,128,217,128,218,2,1,203,1,204,18,3,188,3,190,36,7,200,7,
80410204,16,15,192,15,201,64,34,32,34,49,32,72,192,72,225,64,220,0,220,65,1,236,
804111,236,140,4,96,4,97,34,9,20,9,22,108,19,4,19,8,56,38,128,38,138,193,224,1,
80412224,25,99,212,3,212,44,7,214,71,212,66,22,51,150,52,3,44,128,44,129,100,89,
80413214,89,216,10,153,2,153,4,189,52,5,52,8,202,114,42,114,48,244,230,84,230,
80414103,233,222,105,222,129,83,191,83,191,133,167,160,167,161,10,48,13,48,20,0,
8041532,26,192,26,208,64,56,128,56,192,192,113,64,113,129,1,251,129,252,2,44,
80416114,44,115,4,16,12,56,12,64,32,27,128,27,144,64,211,197,211,198,2,8,6,88,9,
80417164,16,17,216,17,224,47,245,1,120,0,255,1,129,2,83,1,134,2,84,1,142,1,221,
804181,143,2,89,1,144,2,91,1,145,1,146,1,147,2,96,1,148,2,99,1,151,2,104,1,152,
804191,153,1,157,2,114,1,159,2,117,1,167,1,168,1,174,2,136,1,183,2,146,1,241,1,
80420243,1,246,1,149,1,247,1,191,2,32,1,158,2,58,44,101,2,61,1,154,2,62,44,102,
804212,67,1,128,2,68,2,137,2,69,2,140,3,118,3,119,3,134,3,172,3,140,3,204,3,207,
804223,215,3,244,3,184,3,249,3,242,4,192,4,207,30,158,0,223,31,188,31,179,31,
80423204,31,195,31,236,31,229,31,252,31,243,33,38,3,201,33,42,0,107,33,43,0,229,
8042433,50,33,78,33,131,33,132,44,96,44,97,44,98,2,107,44,99,29,125,44,100,2,
80425125,44,109,2,81,44,110,2,113,44,111,2,80,44,112,2,82,167,125,29,121,167,
80426141,2,101,2,2,97,0,52,129,131,128,
80427};
11fdf7f2
TL
80428
80429#if defined(DUK_USE_REGEXP_CANON_WORKAROUND)
80430/*
80431 * Automatically generated by extract_caseconv.py, do not edit!
80432 */
80433
80434const duk_uint16_t duk_unicode_re_canon_lookup[65536] = {
804350,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,
8043628,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,
8043753,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,
8043878,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,65,66,67,68,69,70,
8043971,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,123,124,125,
80440126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
80441144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,
80442162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,
80443180,924,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,
80444198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,
80445216,217,218,219,220,221,222,223,192,193,194,195,196,197,198,199,200,201,
80446202,203,204,205,206,207,208,209,210,211,212,213,214,247,216,217,218,219,
80447220,221,222,376,256,256,258,258,260,260,262,262,264,264,266,266,268,268,
80448270,270,272,272,274,274,276,276,278,278,280,280,282,282,284,284,286,286,
80449288,288,290,290,292,292,294,294,296,296,298,298,300,300,302,302,304,305,
80450306,306,308,308,310,310,312,313,313,315,315,317,317,319,319,321,321,323,
80451323,325,325,327,327,329,330,330,332,332,334,334,336,336,338,338,340,340,
80452342,342,344,344,346,346,348,348,350,350,352,352,354,354,356,356,358,358,
80453360,360,362,362,364,364,366,366,368,368,370,370,372,372,374,374,376,377,
80454377,379,379,381,381,383,579,385,386,386,388,388,390,391,391,393,394,395,
80455395,397,398,399,400,401,401,403,404,502,406,407,408,408,573,411,412,413,
80456544,415,416,416,418,418,420,420,422,423,423,425,426,427,428,428,430,431,
80457431,433,434,435,435,437,437,439,440,440,442,443,444,444,446,503,448,449,
80458450,451,452,452,452,455,455,455,458,458,458,461,461,463,463,465,465,467,
80459467,469,469,471,471,473,473,475,475,398,478,478,480,480,482,482,484,484,
80460486,486,488,488,490,490,492,492,494,494,496,497,497,497,500,500,502,503,
80461504,504,506,506,508,508,510,510,512,512,514,514,516,516,518,518,520,520,
80462522,522,524,524,526,526,528,528,530,530,532,532,534,534,536,536,538,538,
80463540,540,542,542,544,545,546,546,548,548,550,550,552,552,554,554,556,556,
80464558,558,560,560,562,562,564,565,566,567,568,569,570,571,571,573,574,11390,
8046511391,577,577,579,580,581,582,582,584,584,586,586,588,588,590,590,11375,
8046611373,11376,385,390,597,393,394,600,399,602,400,604,605,606,607,403,609,
80467610,404,612,42893L,614,615,407,406,618,11362,620,621,622,412,624,11374,413,
80468627,628,415,630,631,632,633,634,635,636,11364,638,639,422,641,642,425,644,
80469645,646,647,430,580,433,434,581,653,654,655,656,657,439,659,660,661,662,
80470663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,678,679,680,
80471681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,
80472699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715,716,
80473717,718,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733,734,
80474735,736,737,738,739,740,741,742,743,744,745,746,747,748,749,750,751,752,
80475753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,
80476771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,
80477789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,
80478807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,
80479825,826,827,828,829,830,831,832,833,834,835,836,921,838,839,840,841,842,
80480843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,
80481861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,
80482879,880,880,882,882,884,885,886,886,888,889,890,1021,1022,1023,894,895,896,
80483897,898,899,900,901,902,903,904,905,906,907,908,909,910,911,912,913,914,
80484915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,930,931,932,
80485933,934,935,936,937,938,939,902,904,905,906,944,913,914,915,916,917,918,
80486919,920,921,922,923,924,925,926,927,928,929,931,931,932,933,934,935,936,
80487937,938,939,908,910,911,975,914,920,978,979,980,934,928,975,984,984,986,
80488986,988,988,990,990,992,992,994,994,996,996,998,998,1000,1000,1002,1002,
804891004,1004,1006,1006,922,929,1017,1011,1012,917,1014,1015,1015,1017,1018,
804901018,1020,1021,1022,1023,1024,1025,1026,1027,1028,1029,1030,1031,1032,1033,
804911034,1035,1036,1037,1038,1039,1040,1041,1042,1043,1044,1045,1046,1047,1048,
804921049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,
804931064,1065,1066,1067,1068,1069,1070,1071,1040,1041,1042,1043,1044,1045,1046,
804941047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,
804951062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1024,1025,1026,1027,1028,
804961029,1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,1120,1120,1122,1122,
804971124,1124,1126,1126,1128,1128,1130,1130,1132,1132,1134,1134,1136,1136,1138,
804981138,1140,1140,1142,1142,1144,1144,1146,1146,1148,1148,1150,1150,1152,1152,
804991154,1155,1156,1157,1158,1159,1160,1161,1162,1162,1164,1164,1166,1166,1168,
805001168,1170,1170,1172,1172,1174,1174,1176,1176,1178,1178,1180,1180,1182,1182,
805011184,1184,1186,1186,1188,1188,1190,1190,1192,1192,1194,1194,1196,1196,1198,
805021198,1200,1200,1202,1202,1204,1204,1206,1206,1208,1208,1210,1210,1212,1212,
805031214,1214,1216,1217,1217,1219,1219,1221,1221,1223,1223,1225,1225,1227,1227,
805041229,1229,1216,1232,1232,1234,1234,1236,1236,1238,1238,1240,1240,1242,1242,
805051244,1244,1246,1246,1248,1248,1250,1250,1252,1252,1254,1254,1256,1256,1258,
805061258,1260,1260,1262,1262,1264,1264,1266,1266,1268,1268,1270,1270,1272,1272,
805071274,1274,1276,1276,1278,1278,1280,1280,1282,1282,1284,1284,1286,1286,1288,
805081288,1290,1290,1292,1292,1294,1294,1296,1296,1298,1298,1300,1300,1302,1302,
805091304,1304,1306,1306,1308,1308,1310,1310,1312,1312,1314,1314,1316,1316,1318,
805101318,1320,1321,1322,1323,1324,1325,1326,1327,1328,1329,1330,1331,1332,1333,
805111334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344,1345,1346,1347,1348,
805121349,1350,1351,1352,1353,1354,1355,1356,1357,1358,1359,1360,1361,1362,1363,
805131364,1365,1366,1367,1368,1369,1370,1371,1372,1373,1374,1375,1376,1329,1330,
805141331,1332,1333,1334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344,1345,
805151346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356,1357,1358,1359,1360,
805161361,1362,1363,1364,1365,1366,1415,1416,1417,1418,1419,1420,1421,1422,1423,
805171424,1425,1426,1427,1428,1429,1430,1431,1432,1433,1434,1435,1436,1437,1438,
805181439,1440,1441,1442,1443,1444,1445,1446,1447,1448,1449,1450,1451,1452,1453,
805191454,1455,1456,1457,1458,1459,1460,1461,1462,1463,1464,1465,1466,1467,1468,
805201469,1470,1471,1472,1473,1474,1475,1476,1477,1478,1479,1480,1481,1482,1483,
805211484,1485,1486,1487,1488,1489,1490,1491,1492,1493,1494,1495,1496,1497,1498,
805221499,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511,1512,1513,
805231514,1515,1516,1517,1518,1519,1520,1521,1522,1523,1524,1525,1526,1527,1528,
805241529,1530,1531,1532,1533,1534,1535,1536,1537,1538,1539,1540,1541,1542,1543,
805251544,1545,1546,1547,1548,1549,1550,1551,1552,1553,1554,1555,1556,1557,1558,
805261559,1560,1561,1562,1563,1564,1565,1566,1567,1568,1569,1570,1571,1572,1573,
805271574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,1585,1586,1587,1588,
805281589,1590,1591,1592,1593,1594,1595,1596,1597,1598,1599,1600,1601,1602,1603,
805291604,1605,1606,1607,1608,1609,1610,1611,1612,1613,1614,1615,1616,1617,1618,
805301619,1620,1621,1622,1623,1624,1625,1626,1627,1628,1629,1630,1631,1632,1633,
805311634,1635,1636,1637,1638,1639,1640,1641,1642,1643,1644,1645,1646,1647,1648,
805321649,1650,1651,1652,1653,1654,1655,1656,1657,1658,1659,1660,1661,1662,1663,
805331664,1665,1666,1667,1668,1669,1670,1671,1672,1673,1674,1675,1676,1677,1678,
805341679,1680,1681,1682,1683,1684,1685,1686,1687,1688,1689,1690,1691,1692,1693,
805351694,1695,1696,1697,1698,1699,1700,1701,1702,1703,1704,1705,1706,1707,1708,
805361709,1710,1711,1712,1713,1714,1715,1716,1717,1718,1719,1720,1721,1722,1723,
805371724,1725,1726,1727,1728,1729,1730,1731,1732,1733,1734,1735,1736,1737,1738,
805381739,1740,1741,1742,1743,1744,1745,1746,1747,1748,1749,1750,1751,1752,1753,
805391754,1755,1756,1757,1758,1759,1760,1761,1762,1763,1764,1765,1766,1767,1768,
805401769,1770,1771,1772,1773,1774,1775,1776,1777,1778,1779,1780,1781,1782,1783,
805411784,1785,1786,1787,1788,1789,1790,1791,1792,1793,1794,1795,1796,1797,1798,
805421799,1800,1801,1802,1803,1804,1805,1806,1807,1808,1809,1810,1811,1812,1813,
805431814,1815,1816,1817,1818,1819,1820,1821,1822,1823,1824,1825,1826,1827,1828,
805441829,1830,1831,1832,1833,1834,1835,1836,1837,1838,1839,1840,1841,1842,1843,
805451844,1845,1846,1847,1848,1849,1850,1851,1852,1853,1854,1855,1856,1857,1858,
805461859,1860,1861,1862,1863,1864,1865,1866,1867,1868,1869,1870,1871,1872,1873,
805471874,1875,1876,1877,1878,1879,1880,1881,1882,1883,1884,1885,1886,1887,1888,
805481889,1890,1891,1892,1893,1894,1895,1896,1897,1898,1899,1900,1901,1902,1903,
805491904,1905,1906,1907,1908,1909,1910,1911,1912,1913,1914,1915,1916,1917,1918,
805501919,1920,1921,1922,1923,1924,1925,1926,1927,1928,1929,1930,1931,1932,1933,
805511934,1935,1936,1937,1938,1939,1940,1941,1942,1943,1944,1945,1946,1947,1948,
805521949,1950,1951,1952,1953,1954,1955,1956,1957,1958,1959,1960,1961,1962,1963,
805531964,1965,1966,1967,1968,1969,1970,1971,1972,1973,1974,1975,1976,1977,1978,
805541979,1980,1981,1982,1983,1984,1985,1986,1987,1988,1989,1990,1991,1992,1993,
805551994,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,
805562009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022,2023,
805572024,2025,2026,2027,2028,2029,2030,2031,2032,2033,2034,2035,2036,2037,2038,
805582039,2040,2041,2042,2043,2044,2045,2046,2047,2048,2049,2050,2051,2052,2053,
805592054,2055,2056,2057,2058,2059,2060,2061,2062,2063,2064,2065,2066,2067,2068,
805602069,2070,2071,2072,2073,2074,2075,2076,2077,2078,2079,2080,2081,2082,2083,
805612084,2085,2086,2087,2088,2089,2090,2091,2092,2093,2094,2095,2096,2097,2098,
805622099,2100,2101,2102,2103,2104,2105,2106,2107,2108,2109,2110,2111,2112,2113,
805632114,2115,2116,2117,2118,2119,2120,2121,2122,2123,2124,2125,2126,2127,2128,
805642129,2130,2131,2132,2133,2134,2135,2136,2137,2138,2139,2140,2141,2142,2143,
805652144,2145,2146,2147,2148,2149,2150,2151,2152,2153,2154,2155,2156,2157,2158,
805662159,2160,2161,2162,2163,2164,2165,2166,2167,2168,2169,2170,2171,2172,2173,
805672174,2175,2176,2177,2178,2179,2180,2181,2182,2183,2184,2185,2186,2187,2188,
805682189,2190,2191,2192,2193,2194,2195,2196,2197,2198,2199,2200,2201,2202,2203,
805692204,2205,2206,2207,2208,2209,2210,2211,2212,2213,2214,2215,2216,2217,2218,
805702219,2220,2221,2222,2223,2224,2225,2226,2227,2228,2229,2230,2231,2232,2233,
805712234,2235,2236,2237,2238,2239,2240,2241,2242,2243,2244,2245,2246,2247,2248,
805722249,2250,2251,2252,2253,2254,2255,2256,2257,2258,2259,2260,2261,2262,2263,
805732264,2265,2266,2267,2268,2269,2270,2271,2272,2273,2274,2275,2276,2277,2278,
805742279,2280,2281,2282,2283,2284,2285,2286,2287,2288,2289,2290,2291,2292,2293,
805752294,2295,2296,2297,2298,2299,2300,2301,2302,2303,2304,2305,2306,2307,2308,
805762309,2310,2311,2312,2313,2314,2315,2316,2317,2318,2319,2320,2321,2322,2323,
805772324,2325,2326,2327,2328,2329,2330,2331,2332,2333,2334,2335,2336,2337,2338,
805782339,2340,2341,2342,2343,2344,2345,2346,2347,2348,2349,2350,2351,2352,2353,
805792354,2355,2356,2357,2358,2359,2360,2361,2362,2363,2364,2365,2366,2367,2368,
805802369,2370,2371,2372,2373,2374,2375,2376,2377,2378,2379,2380,2381,2382,2383,
805812384,2385,2386,2387,2388,2389,2390,2391,2392,2393,2394,2395,2396,2397,2398,
805822399,2400,2401,2402,2403,2404,2405,2406,2407,2408,2409,2410,2411,2412,2413,
805832414,2415,2416,2417,2418,2419,2420,2421,2422,2423,2424,2425,2426,2427,2428,
805842429,2430,2431,2432,2433,2434,2435,2436,2437,2438,2439,2440,2441,2442,2443,
805852444,2445,2446,2447,2448,2449,2450,2451,2452,2453,2454,2455,2456,2457,2458,
805862459,2460,2461,2462,2463,2464,2465,2466,2467,2468,2469,2470,2471,2472,2473,
805872474,2475,2476,2477,2478,2479,2480,2481,2482,2483,2484,2485,2486,2487,2488,
805882489,2490,2491,2492,2493,2494,2495,2496,2497,2498,2499,2500,2501,2502,2503,
805892504,2505,2506,2507,2508,2509,2510,2511,2512,2513,2514,2515,2516,2517,2518,
805902519,2520,2521,2522,2523,2524,2525,2526,2527,2528,2529,2530,2531,2532,2533,
805912534,2535,2536,2537,2538,2539,2540,2541,2542,2543,2544,2545,2546,2547,2548,
805922549,2550,2551,2552,2553,2554,2555,2556,2557,2558,2559,2560,2561,2562,2563,
805932564,2565,2566,2567,2568,2569,2570,2571,2572,2573,2574,2575,2576,2577,2578,
805942579,2580,2581,2582,2583,2584,2585,2586,2587,2588,2589,2590,2591,2592,2593,
805952594,2595,2596,2597,2598,2599,2600,2601,2602,2603,2604,2605,2606,2607,2608,
805962609,2610,2611,2612,2613,2614,2615,2616,2617,2618,2619,2620,2621,2622,2623,
805972624,2625,2626,2627,2628,2629,2630,2631,2632,2633,2634,2635,2636,2637,2638,
805982639,2640,2641,2642,2643,2644,2645,2646,2647,2648,2649,2650,2651,2652,2653,
805992654,2655,2656,2657,2658,2659,2660,2661,2662,2663,2664,2665,2666,2667,2668,
806002669,2670,2671,2672,2673,2674,2675,2676,2677,2678,2679,2680,2681,2682,2683,
806012684,2685,2686,2687,2688,2689,2690,2691,2692,2693,2694,2695,2696,2697,2698,
806022699,2700,2701,2702,2703,2704,2705,2706,2707,2708,2709,2710,2711,2712,2713,
806032714,2715,2716,2717,2718,2719,2720,2721,2722,2723,2724,2725,2726,2727,2728,
806042729,2730,2731,2732,2733,2734,2735,2736,2737,2738,2739,2740,2741,2742,2743,
806052744,2745,2746,2747,2748,2749,2750,2751,2752,2753,2754,2755,2756,2757,2758,
806062759,2760,2761,2762,2763,2764,2765,2766,2767,2768,2769,2770,2771,2772,2773,
806072774,2775,2776,2777,2778,2779,2780,2781,2782,2783,2784,2785,2786,2787,2788,
806082789,2790,2791,2792,2793,2794,2795,2796,2797,2798,2799,2800,2801,2802,2803,
806092804,2805,2806,2807,2808,2809,2810,2811,2812,2813,2814,2815,2816,2817,2818,
806102819,2820,2821,2822,2823,2824,2825,2826,2827,2828,2829,2830,2831,2832,2833,
806112834,2835,2836,2837,2838,2839,2840,2841,2842,2843,2844,2845,2846,2847,2848,
806122849,2850,2851,2852,2853,2854,2855,2856,2857,2858,2859,2860,2861,2862,2863,
806132864,2865,2866,2867,2868,2869,2870,2871,2872,2873,2874,2875,2876,2877,2878,
806142879,2880,2881,2882,2883,2884,2885,2886,2887,2888,2889,2890,2891,2892,2893,
806152894,2895,2896,2897,2898,2899,2900,2901,2902,2903,2904,2905,2906,2907,2908,
806162909,2910,2911,2912,2913,2914,2915,2916,2917,2918,2919,2920,2921,2922,2923,
806172924,2925,2926,2927,2928,2929,2930,2931,2932,2933,2934,2935,2936,2937,2938,
806182939,2940,2941,2942,2943,2944,2945,2946,2947,2948,2949,2950,2951,2952,2953,
806192954,2955,2956,2957,2958,2959,2960,2961,2962,2963,2964,2965,2966,2967,2968,
806202969,2970,2971,2972,2973,2974,2975,2976,2977,2978,2979,2980,2981,2982,2983,
806212984,2985,2986,2987,2988,2989,2990,2991,2992,2993,2994,2995,2996,2997,2998,
806222999,3000,3001,3002,3003,3004,3005,3006,3007,3008,3009,3010,3011,3012,3013,
806233014,3015,3016,3017,3018,3019,3020,3021,3022,3023,3024,3025,3026,3027,3028,
806243029,3030,3031,3032,3033,3034,3035,3036,3037,3038,3039,3040,3041,3042,3043,
806253044,3045,3046,3047,3048,3049,3050,3051,3052,3053,3054,3055,3056,3057,3058,
806263059,3060,3061,3062,3063,3064,3065,3066,3067,3068,3069,3070,3071,3072,3073,
806273074,3075,3076,3077,3078,3079,3080,3081,3082,3083,3084,3085,3086,3087,3088,
806283089,3090,3091,3092,3093,3094,3095,3096,3097,3098,3099,3100,3101,3102,3103,
806293104,3105,3106,3107,3108,3109,3110,3111,3112,3113,3114,3115,3116,3117,3118,
806303119,3120,3121,3122,3123,3124,3125,3126,3127,3128,3129,3130,3131,3132,3133,
806313134,3135,3136,3137,3138,3139,3140,3141,3142,3143,3144,3145,3146,3147,3148,
806323149,3150,3151,3152,3153,3154,3155,3156,3157,3158,3159,3160,3161,3162,3163,
806333164,3165,3166,3167,3168,3169,3170,3171,3172,3173,3174,3175,3176,3177,3178,
806343179,3180,3181,3182,3183,3184,3185,3186,3187,3188,3189,3190,3191,3192,3193,
806353194,3195,3196,3197,3198,3199,3200,3201,3202,3203,3204,3205,3206,3207,3208,
806363209,3210,3211,3212,3213,3214,3215,3216,3217,3218,3219,3220,3221,3222,3223,
806373224,3225,3226,3227,3228,3229,3230,3231,3232,3233,3234,3235,3236,3237,3238,
806383239,3240,3241,3242,3243,3244,3245,3246,3247,3248,3249,3250,3251,3252,3253,
806393254,3255,3256,3257,3258,3259,3260,3261,3262,3263,3264,3265,3266,3267,3268,
806403269,3270,3271,3272,3273,3274,3275,3276,3277,3278,3279,3280,3281,3282,3283,
806413284,3285,3286,3287,3288,3289,3290,3291,3292,3293,3294,3295,3296,3297,3298,
806423299,3300,3301,3302,3303,3304,3305,3306,3307,3308,3309,3310,3311,3312,3313,
806433314,3315,3316,3317,3318,3319,3320,3321,3322,3323,3324,3325,3326,3327,3328,
806443329,3330,3331,3332,3333,3334,3335,3336,3337,3338,3339,3340,3341,3342,3343,
806453344,3345,3346,3347,3348,3349,3350,3351,3352,3353,3354,3355,3356,3357,3358,
806463359,3360,3361,3362,3363,3364,3365,3366,3367,3368,3369,3370,3371,3372,3373,
806473374,3375,3376,3377,3378,3379,3380,3381,3382,3383,3384,3385,3386,3387,3388,
806483389,3390,3391,3392,3393,3394,3395,3396,3397,3398,3399,3400,3401,3402,3403,
806493404,3405,3406,3407,3408,3409,3410,3411,3412,3413,3414,3415,3416,3417,3418,
806503419,3420,3421,3422,3423,3424,3425,3426,3427,3428,3429,3430,3431,3432,3433,
806513434,3435,3436,3437,3438,3439,3440,3441,3442,3443,3444,3445,3446,3447,3448,
806523449,3450,3451,3452,3453,3454,3455,3456,3457,3458,3459,3460,3461,3462,3463,
806533464,3465,3466,3467,3468,3469,3470,3471,3472,3473,3474,3475,3476,3477,3478,
806543479,3480,3481,3482,3483,3484,3485,3486,3487,3488,3489,3490,3491,3492,3493,
806553494,3495,3496,3497,3498,3499,3500,3501,3502,3503,3504,3505,3506,3507,3508,
806563509,3510,3511,3512,3513,3514,3515,3516,3517,3518,3519,3520,3521,3522,3523,
806573524,3525,3526,3527,3528,3529,3530,3531,3532,3533,3534,3535,3536,3537,3538,
806583539,3540,3541,3542,3543,3544,3545,3546,3547,3548,3549,3550,3551,3552,3553,
806593554,3555,3556,3557,3558,3559,3560,3561,3562,3563,3564,3565,3566,3567,3568,
806603569,3570,3571,3572,3573,3574,3575,3576,3577,3578,3579,3580,3581,3582,3583,
806613584,3585,3586,3587,3588,3589,3590,3591,3592,3593,3594,3595,3596,3597,3598,
806623599,3600,3601,3602,3603,3604,3605,3606,3607,3608,3609,3610,3611,3612,3613,
806633614,3615,3616,3617,3618,3619,3620,3621,3622,3623,3624,3625,3626,3627,3628,
806643629,3630,3631,3632,3633,3634,3635,3636,3637,3638,3639,3640,3641,3642,3643,
806653644,3645,3646,3647,3648,3649,3650,3651,3652,3653,3654,3655,3656,3657,3658,
806663659,3660,3661,3662,3663,3664,3665,3666,3667,3668,3669,3670,3671,3672,3673,
806673674,3675,3676,3677,3678,3679,3680,3681,3682,3683,3684,3685,3686,3687,3688,
806683689,3690,3691,3692,3693,3694,3695,3696,3697,3698,3699,3700,3701,3702,3703,
806693704,3705,3706,3707,3708,3709,3710,3711,3712,3713,3714,3715,3716,3717,3718,
806703719,3720,3721,3722,3723,3724,3725,3726,3727,3728,3729,3730,3731,3732,3733,
806713734,3735,3736,3737,3738,3739,3740,3741,3742,3743,3744,3745,3746,3747,3748,
806723749,3750,3751,3752,3753,3754,3755,3756,3757,3758,3759,3760,3761,3762,3763,
806733764,3765,3766,3767,3768,3769,3770,3771,3772,3773,3774,3775,3776,3777,3778,
806743779,3780,3781,3782,3783,3784,3785,3786,3787,3788,3789,3790,3791,3792,3793,
806753794,3795,3796,3797,3798,3799,3800,3801,3802,3803,3804,3805,3806,3807,3808,
806763809,3810,3811,3812,3813,3814,3815,3816,3817,3818,3819,3820,3821,3822,3823,
806773824,3825,3826,3827,3828,3829,3830,3831,3832,3833,3834,3835,3836,3837,3838,
806783839,3840,3841,3842,3843,3844,3845,3846,3847,3848,3849,3850,3851,3852,3853,
806793854,3855,3856,3857,3858,3859,3860,3861,3862,3863,3864,3865,3866,3867,3868,
806803869,3870,3871,3872,3873,3874,3875,3876,3877,3878,3879,3880,3881,3882,3883,
806813884,3885,3886,3887,3888,3889,3890,3891,3892,3893,3894,3895,3896,3897,3898,
806823899,3900,3901,3902,3903,3904,3905,3906,3907,3908,3909,3910,3911,3912,3913,
806833914,3915,3916,3917,3918,3919,3920,3921,3922,3923,3924,3925,3926,3927,3928,
806843929,3930,3931,3932,3933,3934,3935,3936,3937,3938,3939,3940,3941,3942,3943,
806853944,3945,3946,3947,3948,3949,3950,3951,3952,3953,3954,3955,3956,3957,3958,
806863959,3960,3961,3962,3963,3964,3965,3966,3967,3968,3969,3970,3971,3972,3973,
806873974,3975,3976,3977,3978,3979,3980,3981,3982,3983,3984,3985,3986,3987,3988,
806883989,3990,3991,3992,3993,3994,3995,3996,3997,3998,3999,4000,4001,4002,4003,
806894004,4005,4006,4007,4008,4009,4010,4011,4012,4013,4014,4015,4016,4017,4018,
806904019,4020,4021,4022,4023,4024,4025,4026,4027,4028,4029,4030,4031,4032,4033,
806914034,4035,4036,4037,4038,4039,4040,4041,4042,4043,4044,4045,4046,4047,4048,
806924049,4050,4051,4052,4053,4054,4055,4056,4057,4058,4059,4060,4061,4062,4063,
806934064,4065,4066,4067,4068,4069,4070,4071,4072,4073,4074,4075,4076,4077,4078,
806944079,4080,4081,4082,4083,4084,4085,4086,4087,4088,4089,4090,4091,4092,4093,
806954094,4095,4096,4097,4098,4099,4100,4101,4102,4103,4104,4105,4106,4107,4108,
806964109,4110,4111,4112,4113,4114,4115,4116,4117,4118,4119,4120,4121,4122,4123,
806974124,4125,4126,4127,4128,4129,4130,4131,4132,4133,4134,4135,4136,4137,4138,
806984139,4140,4141,4142,4143,4144,4145,4146,4147,4148,4149,4150,4151,4152,4153,
806994154,4155,4156,4157,4158,4159,4160,4161,4162,4163,4164,4165,4166,4167,4168,
807004169,4170,4171,4172,4173,4174,4175,4176,4177,4178,4179,4180,4181,4182,4183,
807014184,4185,4186,4187,4188,4189,4190,4191,4192,4193,4194,4195,4196,4197,4198,
807024199,4200,4201,4202,4203,4204,4205,4206,4207,4208,4209,4210,4211,4212,4213,
807034214,4215,4216,4217,4218,4219,4220,4221,4222,4223,4224,4225,4226,4227,4228,
807044229,4230,4231,4232,4233,4234,4235,4236,4237,4238,4239,4240,4241,4242,4243,
807054244,4245,4246,4247,4248,4249,4250,4251,4252,4253,4254,4255,4256,4257,4258,
807064259,4260,4261,4262,4263,4264,4265,4266,4267,4268,4269,4270,4271,4272,4273,
807074274,4275,4276,4277,4278,4279,4280,4281,4282,4283,4284,4285,4286,4287,4288,
807084289,4290,4291,4292,4293,4294,4295,4296,4297,4298,4299,4300,4301,4302,4303,
807094304,4305,4306,4307,4308,4309,4310,4311,4312,4313,4314,4315,4316,4317,4318,
807104319,4320,4321,4322,4323,4324,4325,4326,4327,4328,4329,4330,4331,4332,4333,
807114334,4335,4336,4337,4338,4339,4340,4341,4342,4343,4344,4345,4346,4347,4348,
807124349,4350,4351,4352,4353,4354,4355,4356,4357,4358,4359,4360,4361,4362,4363,
807134364,4365,4366,4367,4368,4369,4370,4371,4372,4373,4374,4375,4376,4377,4378,
807144379,4380,4381,4382,4383,4384,4385,4386,4387,4388,4389,4390,4391,4392,4393,
807154394,4395,4396,4397,4398,4399,4400,4401,4402,4403,4404,4405,4406,4407,4408,
807164409,4410,4411,4412,4413,4414,4415,4416,4417,4418,4419,4420,4421,4422,4423,
807174424,4425,4426,4427,4428,4429,4430,4431,4432,4433,4434,4435,4436,4437,4438,
807184439,4440,4441,4442,4443,4444,4445,4446,4447,4448,4449,4450,4451,4452,4453,
807194454,4455,4456,4457,4458,4459,4460,4461,4462,4463,4464,4465,4466,4467,4468,
807204469,4470,4471,4472,4473,4474,4475,4476,4477,4478,4479,4480,4481,4482,4483,
807214484,4485,4486,4487,4488,4489,4490,4491,4492,4493,4494,4495,4496,4497,4498,
807224499,4500,4501,4502,4503,4504,4505,4506,4507,4508,4509,4510,4511,4512,4513,
807234514,4515,4516,4517,4518,4519,4520,4521,4522,4523,4524,4525,4526,4527,4528,
807244529,4530,4531,4532,4533,4534,4535,4536,4537,4538,4539,4540,4541,4542,4543,
807254544,4545,4546,4547,4548,4549,4550,4551,4552,4553,4554,4555,4556,4557,4558,
807264559,4560,4561,4562,4563,4564,4565,4566,4567,4568,4569,4570,4571,4572,4573,
807274574,4575,4576,4577,4578,4579,4580,4581,4582,4583,4584,4585,4586,4587,4588,
807284589,4590,4591,4592,4593,4594,4595,4596,4597,4598,4599,4600,4601,4602,4603,
807294604,4605,4606,4607,4608,4609,4610,4611,4612,4613,4614,4615,4616,4617,4618,
807304619,4620,4621,4622,4623,4624,4625,4626,4627,4628,4629,4630,4631,4632,4633,
807314634,4635,4636,4637,4638,4639,4640,4641,4642,4643,4644,4645,4646,4647,4648,
807324649,4650,4651,4652,4653,4654,4655,4656,4657,4658,4659,4660,4661,4662,4663,
807334664,4665,4666,4667,4668,4669,4670,4671,4672,4673,4674,4675,4676,4677,4678,
807344679,4680,4681,4682,4683,4684,4685,4686,4687,4688,4689,4690,4691,4692,4693,
807354694,4695,4696,4697,4698,4699,4700,4701,4702,4703,4704,4705,4706,4707,4708,
807364709,4710,4711,4712,4713,4714,4715,4716,4717,4718,4719,4720,4721,4722,4723,
807374724,4725,4726,4727,4728,4729,4730,4731,4732,4733,4734,4735,4736,4737,4738,
807384739,4740,4741,4742,4743,4744,4745,4746,4747,4748,4749,4750,4751,4752,4753,
807394754,4755,4756,4757,4758,4759,4760,4761,4762,4763,4764,4765,4766,4767,4768,
807404769,4770,4771,4772,4773,4774,4775,4776,4777,4778,4779,4780,4781,4782,4783,
807414784,4785,4786,4787,4788,4789,4790,4791,4792,4793,4794,4795,4796,4797,4798,
807424799,4800,4801,4802,4803,4804,4805,4806,4807,4808,4809,4810,4811,4812,4813,
807434814,4815,4816,4817,4818,4819,4820,4821,4822,4823,4824,4825,4826,4827,4828,
807444829,4830,4831,4832,4833,4834,4835,4836,4837,4838,4839,4840,4841,4842,4843,
807454844,4845,4846,4847,4848,4849,4850,4851,4852,4853,4854,4855,4856,4857,4858,
807464859,4860,4861,4862,4863,4864,4865,4866,4867,4868,4869,4870,4871,4872,4873,
807474874,4875,4876,4877,4878,4879,4880,4881,4882,4883,4884,4885,4886,4887,4888,
807484889,4890,4891,4892,4893,4894,4895,4896,4897,4898,4899,4900,4901,4902,4903,
807494904,4905,4906,4907,4908,4909,4910,4911,4912,4913,4914,4915,4916,4917,4918,
807504919,4920,4921,4922,4923,4924,4925,4926,4927,4928,4929,4930,4931,4932,4933,
807514934,4935,4936,4937,4938,4939,4940,4941,4942,4943,4944,4945,4946,4947,4948,
807524949,4950,4951,4952,4953,4954,4955,4956,4957,4958,4959,4960,4961,4962,4963,
807534964,4965,4966,4967,4968,4969,4970,4971,4972,4973,4974,4975,4976,4977,4978,
807544979,4980,4981,4982,4983,4984,4985,4986,4987,4988,4989,4990,4991,4992,4993,
807554994,4995,4996,4997,4998,4999,5000,5001,5002,5003,5004,5005,5006,5007,5008,
807565009,5010,5011,5012,5013,5014,5015,5016,5017,5018,5019,5020,5021,5022,5023,
807575024,5025,5026,5027,5028,5029,5030,5031,5032,5033,5034,5035,5036,5037,5038,
807585039,5040,5041,5042,5043,5044,5045,5046,5047,5048,5049,5050,5051,5052,5053,
807595054,5055,5056,5057,5058,5059,5060,5061,5062,5063,5064,5065,5066,5067,5068,
807605069,5070,5071,5072,5073,5074,5075,5076,5077,5078,5079,5080,5081,5082,5083,
807615084,5085,5086,5087,5088,5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,
807625099,5100,5101,5102,5103,5104,5105,5106,5107,5108,5109,5110,5111,5112,5113,
807635114,5115,5116,5117,5118,5119,5120,5121,5122,5123,5124,5125,5126,5127,5128,
807645129,5130,5131,5132,5133,5134,5135,5136,5137,5138,5139,5140,5141,5142,5143,
807655144,5145,5146,5147,5148,5149,5150,5151,5152,5153,5154,5155,5156,5157,5158,
807665159,5160,5161,5162,5163,5164,5165,5166,5167,5168,5169,5170,5171,5172,5173,
807675174,5175,5176,5177,5178,5179,5180,5181,5182,5183,5184,5185,5186,5187,5188,
807685189,5190,5191,5192,5193,5194,5195,5196,5197,5198,5199,5200,5201,5202,5203,
807695204,5205,5206,5207,5208,5209,5210,5211,5212,5213,5214,5215,5216,5217,5218,
807705219,5220,5221,5222,5223,5224,5225,5226,5227,5228,5229,5230,5231,5232,5233,
807715234,5235,5236,5237,5238,5239,5240,5241,5242,5243,5244,5245,5246,5247,5248,
807725249,5250,5251,5252,5253,5254,5255,5256,5257,5258,5259,5260,5261,5262,5263,
807735264,5265,5266,5267,5268,5269,5270,5271,5272,5273,5274,5275,5276,5277,5278,
807745279,5280,5281,5282,5283,5284,5285,5286,5287,5288,5289,5290,5291,5292,5293,
807755294,5295,5296,5297,5298,5299,5300,5301,5302,5303,5304,5305,5306,5307,5308,
807765309,5310,5311,5312,5313,5314,5315,5316,5317,5318,5319,5320,5321,5322,5323,
807775324,5325,5326,5327,5328,5329,5330,5331,5332,5333,5334,5335,5336,5337,5338,
807785339,5340,5341,5342,5343,5344,5345,5346,5347,5348,5349,5350,5351,5352,5353,
807795354,5355,5356,5357,5358,5359,5360,5361,5362,5363,5364,5365,5366,5367,5368,
807805369,5370,5371,5372,5373,5374,5375,5376,5377,5378,5379,5380,5381,5382,5383,
807815384,5385,5386,5387,5388,5389,5390,5391,5392,5393,5394,5395,5396,5397,5398,
807825399,5400,5401,5402,5403,5404,5405,5406,5407,5408,5409,5410,5411,5412,5413,
807835414,5415,5416,5417,5418,5419,5420,5421,5422,5423,5424,5425,5426,5427,5428,
807845429,5430,5431,5432,5433,5434,5435,5436,5437,5438,5439,5440,5441,5442,5443,
807855444,5445,5446,5447,5448,5449,5450,5451,5452,5453,5454,5455,5456,5457,5458,
807865459,5460,5461,5462,5463,5464,5465,5466,5467,5468,5469,5470,5471,5472,5473,
807875474,5475,5476,5477,5478,5479,5480,5481,5482,5483,5484,5485,5486,5487,5488,
807885489,5490,5491,5492,5493,5494,5495,5496,5497,5498,5499,5500,5501,5502,5503,
807895504,5505,5506,5507,5508,5509,5510,5511,5512,5513,5514,5515,5516,5517,5518,
807905519,5520,5521,5522,5523,5524,5525,5526,5527,5528,5529,5530,5531,5532,5533,
807915534,5535,5536,5537,5538,5539,5540,5541,5542,5543,5544,5545,5546,5547,5548,
807925549,5550,5551,5552,5553,5554,5555,5556,5557,5558,5559,5560,5561,5562,5563,
807935564,5565,5566,5567,5568,5569,5570,5571,5572,5573,5574,5575,5576,5577,5578,
807945579,5580,5581,5582,5583,5584,5585,5586,5587,5588,5589,5590,5591,5592,5593,
807955594,5595,5596,5597,5598,5599,5600,5601,5602,5603,5604,5605,5606,5607,5608,
807965609,5610,5611,5612,5613,5614,5615,5616,5617,5618,5619,5620,5621,5622,5623,
807975624,5625,5626,5627,5628,5629,5630,5631,5632,5633,5634,5635,5636,5637,5638,
807985639,5640,5641,5642,5643,5644,5645,5646,5647,5648,5649,5650,5651,5652,5653,
807995654,5655,5656,5657,5658,5659,5660,5661,5662,5663,5664,5665,5666,5667,5668,
808005669,5670,5671,5672,5673,5674,5675,5676,5677,5678,5679,5680,5681,5682,5683,
808015684,5685,5686,5687,5688,5689,5690,5691,5692,5693,5694,5695,5696,5697,5698,
808025699,5700,5701,5702,5703,5704,5705,5706,5707,5708,5709,5710,5711,5712,5713,
808035714,5715,5716,5717,5718,5719,5720,5721,5722,5723,5724,5725,5726,5727,5728,
808045729,5730,5731,5732,5733,5734,5735,5736,5737,5738,5739,5740,5741,5742,5743,
808055744,5745,5746,5747,5748,5749,5750,5751,5752,5753,5754,5755,5756,5757,5758,
808065759,5760,5761,5762,5763,5764,5765,5766,5767,5768,5769,5770,5771,5772,5773,
808075774,5775,5776,5777,5778,5779,5780,5781,5782,5783,5784,5785,5786,5787,5788,
808085789,5790,5791,5792,5793,5794,5795,5796,5797,5798,5799,5800,5801,5802,5803,
808095804,5805,5806,5807,5808,5809,5810,5811,5812,5813,5814,5815,5816,5817,5818,
808105819,5820,5821,5822,5823,5824,5825,5826,5827,5828,5829,5830,5831,5832,5833,
808115834,5835,5836,5837,5838,5839,5840,5841,5842,5843,5844,5845,5846,5847,5848,
808125849,5850,5851,5852,5853,5854,5855,5856,5857,5858,5859,5860,5861,5862,5863,
808135864,5865,5866,5867,5868,5869,5870,5871,5872,5873,5874,5875,5876,5877,5878,
808145879,5880,5881,5882,5883,5884,5885,5886,5887,5888,5889,5890,5891,5892,5893,
808155894,5895,5896,5897,5898,5899,5900,5901,5902,5903,5904,5905,5906,5907,5908,
808165909,5910,5911,5912,5913,5914,5915,5916,5917,5918,5919,5920,5921,5922,5923,
808175924,5925,5926,5927,5928,5929,5930,5931,5932,5933,5934,5935,5936,5937,5938,
808185939,5940,5941,5942,5943,5944,5945,5946,5947,5948,5949,5950,5951,5952,5953,
808195954,5955,5956,5957,5958,5959,5960,5961,5962,5963,5964,5965,5966,5967,5968,
808205969,5970,5971,5972,5973,5974,5975,5976,5977,5978,5979,5980,5981,5982,5983,
808215984,5985,5986,5987,5988,5989,5990,5991,5992,5993,5994,5995,5996,5997,5998,
808225999,6000,6001,6002,6003,6004,6005,6006,6007,6008,6009,6010,6011,6012,6013,
808236014,6015,6016,6017,6018,6019,6020,6021,6022,6023,6024,6025,6026,6027,6028,
808246029,6030,6031,6032,6033,6034,6035,6036,6037,6038,6039,6040,6041,6042,6043,
808256044,6045,6046,6047,6048,6049,6050,6051,6052,6053,6054,6055,6056,6057,6058,
808266059,6060,6061,6062,6063,6064,6065,6066,6067,6068,6069,6070,6071,6072,6073,
808276074,6075,6076,6077,6078,6079,6080,6081,6082,6083,6084,6085,6086,6087,6088,
808286089,6090,6091,6092,6093,6094,6095,6096,6097,6098,6099,6100,6101,6102,6103,
808296104,6105,6106,6107,6108,6109,6110,6111,6112,6113,6114,6115,6116,6117,6118,
808306119,6120,6121,6122,6123,6124,6125,6126,6127,6128,6129,6130,6131,6132,6133,
808316134,6135,6136,6137,6138,6139,6140,6141,6142,6143,6144,6145,6146,6147,6148,
808326149,6150,6151,6152,6153,6154,6155,6156,6157,6158,6159,6160,6161,6162,6163,
808336164,6165,6166,6167,6168,6169,6170,6171,6172,6173,6174,6175,6176,6177,6178,
808346179,6180,6181,6182,6183,6184,6185,6186,6187,6188,6189,6190,6191,6192,6193,
808356194,6195,6196,6197,6198,6199,6200,6201,6202,6203,6204,6205,6206,6207,6208,
808366209,6210,6211,6212,6213,6214,6215,6216,6217,6218,6219,6220,6221,6222,6223,
808376224,6225,6226,6227,6228,6229,6230,6231,6232,6233,6234,6235,6236,6237,6238,
808386239,6240,6241,6242,6243,6244,6245,6246,6247,6248,6249,6250,6251,6252,6253,
808396254,6255,6256,6257,6258,6259,6260,6261,6262,6263,6264,6265,6266,6267,6268,
808406269,6270,6271,6272,6273,6274,6275,6276,6277,6278,6279,6280,6281,6282,6283,
808416284,6285,6286,6287,6288,6289,6290,6291,6292,6293,6294,6295,6296,6297,6298,
808426299,6300,6301,6302,6303,6304,6305,6306,6307,6308,6309,6310,6311,6312,6313,
808436314,6315,6316,6317,6318,6319,6320,6321,6322,6323,6324,6325,6326,6327,6328,
808446329,6330,6331,6332,6333,6334,6335,6336,6337,6338,6339,6340,6341,6342,6343,
808456344,6345,6346,6347,6348,6349,6350,6351,6352,6353,6354,6355,6356,6357,6358,
808466359,6360,6361,6362,6363,6364,6365,6366,6367,6368,6369,6370,6371,6372,6373,
808476374,6375,6376,6377,6378,6379,6380,6381,6382,6383,6384,6385,6386,6387,6388,
808486389,6390,6391,6392,6393,6394,6395,6396,6397,6398,6399,6400,6401,6402,6403,
808496404,6405,6406,6407,6408,6409,6410,6411,6412,6413,6414,6415,6416,6417,6418,
808506419,6420,6421,6422,6423,6424,6425,6426,6427,6428,6429,6430,6431,6432,6433,
808516434,6435,6436,6437,6438,6439,6440,6441,6442,6443,6444,6445,6446,6447,6448,
808526449,6450,6451,6452,6453,6454,6455,6456,6457,6458,6459,6460,6461,6462,6463,
808536464,6465,6466,6467,6468,6469,6470,6471,6472,6473,6474,6475,6476,6477,6478,
808546479,6480,6481,6482,6483,6484,6485,6486,6487,6488,6489,6490,6491,6492,6493,
808556494,6495,6496,6497,6498,6499,6500,6501,6502,6503,6504,6505,6506,6507,6508,
808566509,6510,6511,6512,6513,6514,6515,6516,6517,6518,6519,6520,6521,6522,6523,
808576524,6525,6526,6527,6528,6529,6530,6531,6532,6533,6534,6535,6536,6537,6538,
808586539,6540,6541,6542,6543,6544,6545,6546,6547,6548,6549,6550,6551,6552,6553,
808596554,6555,6556,6557,6558,6559,6560,6561,6562,6563,6564,6565,6566,6567,6568,
808606569,6570,6571,6572,6573,6574,6575,6576,6577,6578,6579,6580,6581,6582,6583,
808616584,6585,6586,6587,6588,6589,6590,6591,6592,6593,6594,6595,6596,6597,6598,
808626599,6600,6601,6602,6603,6604,6605,6606,6607,6608,6609,6610,6611,6612,6613,
808636614,6615,6616,6617,6618,6619,6620,6621,6622,6623,6624,6625,6626,6627,6628,
808646629,6630,6631,6632,6633,6634,6635,6636,6637,6638,6639,6640,6641,6642,6643,
808656644,6645,6646,6647,6648,6649,6650,6651,6652,6653,6654,6655,6656,6657,6658,
808666659,6660,6661,6662,6663,6664,6665,6666,6667,6668,6669,6670,6671,6672,6673,
808676674,6675,6676,6677,6678,6679,6680,6681,6682,6683,6684,6685,6686,6687,6688,
808686689,6690,6691,6692,6693,6694,6695,6696,6697,6698,6699,6700,6701,6702,6703,
808696704,6705,6706,6707,6708,6709,6710,6711,6712,6713,6714,6715,6716,6717,6718,
808706719,6720,6721,6722,6723,6724,6725,6726,6727,6728,6729,6730,6731,6732,6733,
808716734,6735,6736,6737,6738,6739,6740,6741,6742,6743,6744,6745,6746,6747,6748,
808726749,6750,6751,6752,6753,6754,6755,6756,6757,6758,6759,6760,6761,6762,6763,
808736764,6765,6766,6767,6768,6769,6770,6771,6772,6773,6774,6775,6776,6777,6778,
808746779,6780,6781,6782,6783,6784,6785,6786,6787,6788,6789,6790,6791,6792,6793,
808756794,6795,6796,6797,6798,6799,6800,6801,6802,6803,6804,6805,6806,6807,6808,
808766809,6810,6811,6812,6813,6814,6815,6816,6817,6818,6819,6820,6821,6822,6823,
808776824,6825,6826,6827,6828,6829,6830,6831,6832,6833,6834,6835,6836,6837,6838,
808786839,6840,6841,6842,6843,6844,6845,6846,6847,6848,6849,6850,6851,6852,6853,
808796854,6855,6856,6857,6858,6859,6860,6861,6862,6863,6864,6865,6866,6867,6868,
808806869,6870,6871,6872,6873,6874,6875,6876,6877,6878,6879,6880,6881,6882,6883,
808816884,6885,6886,6887,6888,6889,6890,6891,6892,6893,6894,6895,6896,6897,6898,
808826899,6900,6901,6902,6903,6904,6905,6906,6907,6908,6909,6910,6911,6912,6913,
808836914,6915,6916,6917,6918,6919,6920,6921,6922,6923,6924,6925,6926,6927,6928,
808846929,6930,6931,6932,6933,6934,6935,6936,6937,6938,6939,6940,6941,6942,6943,
808856944,6945,6946,6947,6948,6949,6950,6951,6952,6953,6954,6955,6956,6957,6958,
808866959,6960,6961,6962,6963,6964,6965,6966,6967,6968,6969,6970,6971,6972,6973,
808876974,6975,6976,6977,6978,6979,6980,6981,6982,6983,6984,6985,6986,6987,6988,
808886989,6990,6991,6992,6993,6994,6995,6996,6997,6998,6999,7000,7001,7002,7003,
808897004,7005,7006,7007,7008,7009,7010,7011,7012,7013,7014,7015,7016,7017,7018,
808907019,7020,7021,7022,7023,7024,7025,7026,7027,7028,7029,7030,7031,7032,7033,
808917034,7035,7036,7037,7038,7039,7040,7041,7042,7043,7044,7045,7046,7047,7048,
808927049,7050,7051,7052,7053,7054,7055,7056,7057,7058,7059,7060,7061,7062,7063,
808937064,7065,7066,7067,7068,7069,7070,7071,7072,7073,7074,7075,7076,7077,7078,
808947079,7080,7081,7082,7083,7084,7085,7086,7087,7088,7089,7090,7091,7092,7093,
808957094,7095,7096,7097,7098,7099,7100,7101,7102,7103,7104,7105,7106,7107,7108,
808967109,7110,7111,7112,7113,7114,7115,7116,7117,7118,7119,7120,7121,7122,7123,
808977124,7125,7126,7127,7128,7129,7130,7131,7132,7133,7134,7135,7136,7137,7138,
808987139,7140,7141,7142,7143,7144,7145,7146,7147,7148,7149,7150,7151,7152,7153,
808997154,7155,7156,7157,7158,7159,7160,7161,7162,7163,7164,7165,7166,7167,7168,
809007169,7170,7171,7172,7173,7174,7175,7176,7177,7178,7179,7180,7181,7182,7183,
809017184,7185,7186,7187,7188,7189,7190,7191,7192,7193,7194,7195,7196,7197,7198,
809027199,7200,7201,7202,7203,7204,7205,7206,7207,7208,7209,7210,7211,7212,7213,
809037214,7215,7216,7217,7218,7219,7220,7221,7222,7223,7224,7225,7226,7227,7228,
809047229,7230,7231,7232,7233,7234,7235,7236,7237,7238,7239,7240,7241,7242,7243,
809057244,7245,7246,7247,7248,7249,7250,7251,7252,7253,7254,7255,7256,7257,7258,
809067259,7260,7261,7262,7263,7264,7265,7266,7267,7268,7269,7270,7271,7272,7273,
809077274,7275,7276,7277,7278,7279,7280,7281,7282,7283,7284,7285,7286,7287,7288,
809087289,7290,7291,7292,7293,7294,7295,7296,7297,7298,7299,7300,7301,7302,7303,
809097304,7305,7306,7307,7308,7309,7310,7311,7312,7313,7314,7315,7316,7317,7318,
809107319,7320,7321,7322,7323,7324,7325,7326,7327,7328,7329,7330,7331,7332,7333,
809117334,7335,7336,7337,7338,7339,7340,7341,7342,7343,7344,7345,7346,7347,7348,
809127349,7350,7351,7352,7353,7354,7355,7356,7357,7358,7359,7360,7361,7362,7363,
809137364,7365,7366,7367,7368,7369,7370,7371,7372,7373,7374,7375,7376,7377,7378,
809147379,7380,7381,7382,7383,7384,7385,7386,7387,7388,7389,7390,7391,7392,7393,
809157394,7395,7396,7397,7398,7399,7400,7401,7402,7403,7404,7405,7406,7407,7408,
809167409,7410,7411,7412,7413,7414,7415,7416,7417,7418,7419,7420,7421,7422,7423,
809177424,7425,7426,7427,7428,7429,7430,7431,7432,7433,7434,7435,7436,7437,7438,
809187439,7440,7441,7442,7443,7444,7445,7446,7447,7448,7449,7450,7451,7452,7453,
809197454,7455,7456,7457,7458,7459,7460,7461,7462,7463,7464,7465,7466,7467,7468,
809207469,7470,7471,7472,7473,7474,7475,7476,7477,7478,7479,7480,7481,7482,7483,
809217484,7485,7486,7487,7488,7489,7490,7491,7492,7493,7494,7495,7496,7497,7498,
809227499,7500,7501,7502,7503,7504,7505,7506,7507,7508,7509,7510,7511,7512,7513,
809237514,7515,7516,7517,7518,7519,7520,7521,7522,7523,7524,7525,7526,7527,7528,
809247529,7530,7531,7532,7533,7534,7535,7536,7537,7538,7539,7540,7541,7542,7543,
809257544,42877L,7546,7547,7548,11363,7550,7551,7552,7553,7554,7555,7556,7557,
809267558,7559,7560,7561,7562,7563,7564,7565,7566,7567,7568,7569,7570,7571,7572,
809277573,7574,7575,7576,7577,7578,7579,7580,7581,7582,7583,7584,7585,7586,7587,
809287588,7589,7590,7591,7592,7593,7594,7595,7596,7597,7598,7599,7600,7601,7602,
809297603,7604,7605,7606,7607,7608,7609,7610,7611,7612,7613,7614,7615,7616,7617,
809307618,7619,7620,7621,7622,7623,7624,7625,7626,7627,7628,7629,7630,7631,7632,
809317633,7634,7635,7636,7637,7638,7639,7640,7641,7642,7643,7644,7645,7646,7647,
809327648,7649,7650,7651,7652,7653,7654,7655,7656,7657,7658,7659,7660,7661,7662,
809337663,7664,7665,7666,7667,7668,7669,7670,7671,7672,7673,7674,7675,7676,7677,
809347678,7679,7680,7680,7682,7682,7684,7684,7686,7686,7688,7688,7690,7690,7692,
809357692,7694,7694,7696,7696,7698,7698,7700,7700,7702,7702,7704,7704,7706,7706,
809367708,7708,7710,7710,7712,7712,7714,7714,7716,7716,7718,7718,7720,7720,7722,
809377722,7724,7724,7726,7726,7728,7728,7730,7730,7732,7732,7734,7734,7736,7736,
809387738,7738,7740,7740,7742,7742,7744,7744,7746,7746,7748,7748,7750,7750,7752,
809397752,7754,7754,7756,7756,7758,7758,7760,7760,7762,7762,7764,7764,7766,7766,
809407768,7768,7770,7770,7772,7772,7774,7774,7776,7776,7778,7778,7780,7780,7782,
809417782,7784,7784,7786,7786,7788,7788,7790,7790,7792,7792,7794,7794,7796,7796,
809427798,7798,7800,7800,7802,7802,7804,7804,7806,7806,7808,7808,7810,7810,7812,
809437812,7814,7814,7816,7816,7818,7818,7820,7820,7822,7822,7824,7824,7826,7826,
809447828,7828,7830,7831,7832,7833,7834,7776,7836,7837,7838,7839,7840,7840,7842,
809457842,7844,7844,7846,7846,7848,7848,7850,7850,7852,7852,7854,7854,7856,7856,
809467858,7858,7860,7860,7862,7862,7864,7864,7866,7866,7868,7868,7870,7870,7872,
809477872,7874,7874,7876,7876,7878,7878,7880,7880,7882,7882,7884,7884,7886,7886,
809487888,7888,7890,7890,7892,7892,7894,7894,7896,7896,7898,7898,7900,7900,7902,
809497902,7904,7904,7906,7906,7908,7908,7910,7910,7912,7912,7914,7914,7916,7916,
809507918,7918,7920,7920,7922,7922,7924,7924,7926,7926,7928,7928,7930,7930,7932,
809517932,7934,7934,7944,7945,7946,7947,7948,7949,7950,7951,7944,7945,7946,7947,
809527948,7949,7950,7951,7960,7961,7962,7963,7964,7965,7958,7959,7960,7961,7962,
809537963,7964,7965,7966,7967,7976,7977,7978,7979,7980,7981,7982,7983,7976,7977,
809547978,7979,7980,7981,7982,7983,7992,7993,7994,7995,7996,7997,7998,7999,7992,
809557993,7994,7995,7996,7997,7998,7999,8008,8009,8010,8011,8012,8013,8006,8007,
809568008,8009,8010,8011,8012,8013,8014,8015,8016,8025,8018,8027,8020,8029,8022,
809578031,8024,8025,8026,8027,8028,8029,8030,8031,8040,8041,8042,8043,8044,8045,
809588046,8047,8040,8041,8042,8043,8044,8045,8046,8047,8122,8123,8136,8137,8138,
809598139,8154,8155,8184,8185,8170,8171,8186,8187,8062,8063,8064,8065,8066,8067,
809608068,8069,8070,8071,8072,8073,8074,8075,8076,8077,8078,8079,8080,8081,8082,
809618083,8084,8085,8086,8087,8088,8089,8090,8091,8092,8093,8094,8095,8096,8097,
809628098,8099,8100,8101,8102,8103,8104,8105,8106,8107,8108,8109,8110,8111,8120,
809638121,8114,8115,8116,8117,8118,8119,8120,8121,8122,8123,8124,8125,921,8127,
809648128,8129,8130,8131,8132,8133,8134,8135,8136,8137,8138,8139,8140,8141,8142,
809658143,8152,8153,8146,8147,8148,8149,8150,8151,8152,8153,8154,8155,8156,8157,
809668158,8159,8168,8169,8162,8163,8164,8172,8166,8167,8168,8169,8170,8171,8172,
809678173,8174,8175,8176,8177,8178,8179,8180,8181,8182,8183,8184,8185,8186,8187,
809688188,8189,8190,8191,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,
809698203,8204,8205,8206,8207,8208,8209,8210,8211,8212,8213,8214,8215,8216,8217,
809708218,8219,8220,8221,8222,8223,8224,8225,8226,8227,8228,8229,8230,8231,8232,
809718233,8234,8235,8236,8237,8238,8239,8240,8241,8242,8243,8244,8245,8246,8247,
809728248,8249,8250,8251,8252,8253,8254,8255,8256,8257,8258,8259,8260,8261,8262,
809738263,8264,8265,8266,8267,8268,8269,8270,8271,8272,8273,8274,8275,8276,8277,
809748278,8279,8280,8281,8282,8283,8284,8285,8286,8287,8288,8289,8290,8291,8292,
809758293,8294,8295,8296,8297,8298,8299,8300,8301,8302,8303,8304,8305,8306,8307,
809768308,8309,8310,8311,8312,8313,8314,8315,8316,8317,8318,8319,8320,8321,8322,
809778323,8324,8325,8326,8327,8328,8329,8330,8331,8332,8333,8334,8335,8336,8337,
809788338,8339,8340,8341,8342,8343,8344,8345,8346,8347,8348,8349,8350,8351,8352,
809798353,8354,8355,8356,8357,8358,8359,8360,8361,8362,8363,8364,8365,8366,8367,
809808368,8369,8370,8371,8372,8373,8374,8375,8376,8377,8378,8379,8380,8381,8382,
809818383,8384,8385,8386,8387,8388,8389,8390,8391,8392,8393,8394,8395,8396,8397,
809828398,8399,8400,8401,8402,8403,8404,8405,8406,8407,8408,8409,8410,8411,8412,
809838413,8414,8415,8416,8417,8418,8419,8420,8421,8422,8423,8424,8425,8426,8427,
809848428,8429,8430,8431,8432,8433,8434,8435,8436,8437,8438,8439,8440,8441,8442,
809858443,8444,8445,8446,8447,8448,8449,8450,8451,8452,8453,8454,8455,8456,8457,
809868458,8459,8460,8461,8462,8463,8464,8465,8466,8467,8468,8469,8470,8471,8472,
809878473,8474,8475,8476,8477,8478,8479,8480,8481,8482,8483,8484,8485,8486,8487,
809888488,8489,8490,8491,8492,8493,8494,8495,8496,8497,8498,8499,8500,8501,8502,
809898503,8504,8505,8506,8507,8508,8509,8510,8511,8512,8513,8514,8515,8516,8517,
809908518,8519,8520,8521,8522,8523,8524,8525,8498,8527,8528,8529,8530,8531,8532,
809918533,8534,8535,8536,8537,8538,8539,8540,8541,8542,8543,8544,8545,8546,8547,
809928548,8549,8550,8551,8552,8553,8554,8555,8556,8557,8558,8559,8544,8545,8546,
809938547,8548,8549,8550,8551,8552,8553,8554,8555,8556,8557,8558,8559,8576,8577,
809948578,8579,8579,8581,8582,8583,8584,8585,8586,8587,8588,8589,8590,8591,8592,
809958593,8594,8595,8596,8597,8598,8599,8600,8601,8602,8603,8604,8605,8606,8607,
809968608,8609,8610,8611,8612,8613,8614,8615,8616,8617,8618,8619,8620,8621,8622,
809978623,8624,8625,8626,8627,8628,8629,8630,8631,8632,8633,8634,8635,8636,8637,
809988638,8639,8640,8641,8642,8643,8644,8645,8646,8647,8648,8649,8650,8651,8652,
809998653,8654,8655,8656,8657,8658,8659,8660,8661,8662,8663,8664,8665,8666,8667,
810008668,8669,8670,8671,8672,8673,8674,8675,8676,8677,8678,8679,8680,8681,8682,
810018683,8684,8685,8686,8687,8688,8689,8690,8691,8692,8693,8694,8695,8696,8697,
810028698,8699,8700,8701,8702,8703,8704,8705,8706,8707,8708,8709,8710,8711,8712,
810038713,8714,8715,8716,8717,8718,8719,8720,8721,8722,8723,8724,8725,8726,8727,
810048728,8729,8730,8731,8732,8733,8734,8735,8736,8737,8738,8739,8740,8741,8742,
810058743,8744,8745,8746,8747,8748,8749,8750,8751,8752,8753,8754,8755,8756,8757,
810068758,8759,8760,8761,8762,8763,8764,8765,8766,8767,8768,8769,8770,8771,8772,
810078773,8774,8775,8776,8777,8778,8779,8780,8781,8782,8783,8784,8785,8786,8787,
810088788,8789,8790,8791,8792,8793,8794,8795,8796,8797,8798,8799,8800,8801,8802,
810098803,8804,8805,8806,8807,8808,8809,8810,8811,8812,8813,8814,8815,8816,8817,
810108818,8819,8820,8821,8822,8823,8824,8825,8826,8827,8828,8829,8830,8831,8832,
810118833,8834,8835,8836,8837,8838,8839,8840,8841,8842,8843,8844,8845,8846,8847,
810128848,8849,8850,8851,8852,8853,8854,8855,8856,8857,8858,8859,8860,8861,8862,
810138863,8864,8865,8866,8867,8868,8869,8870,8871,8872,8873,8874,8875,8876,8877,
810148878,8879,8880,8881,8882,8883,8884,8885,8886,8887,8888,8889,8890,8891,8892,
810158893,8894,8895,8896,8897,8898,8899,8900,8901,8902,8903,8904,8905,8906,8907,
810168908,8909,8910,8911,8912,8913,8914,8915,8916,8917,8918,8919,8920,8921,8922,
810178923,8924,8925,8926,8927,8928,8929,8930,8931,8932,8933,8934,8935,8936,8937,
810188938,8939,8940,8941,8942,8943,8944,8945,8946,8947,8948,8949,8950,8951,8952,
810198953,8954,8955,8956,8957,8958,8959,8960,8961,8962,8963,8964,8965,8966,8967,
810208968,8969,8970,8971,8972,8973,8974,8975,8976,8977,8978,8979,8980,8981,8982,
810218983,8984,8985,8986,8987,8988,8989,8990,8991,8992,8993,8994,8995,8996,8997,
810228998,8999,9000,9001,9002,9003,9004,9005,9006,9007,9008,9009,9010,9011,9012,
810239013,9014,9015,9016,9017,9018,9019,9020,9021,9022,9023,9024,9025,9026,9027,
810249028,9029,9030,9031,9032,9033,9034,9035,9036,9037,9038,9039,9040,9041,9042,
810259043,9044,9045,9046,9047,9048,9049,9050,9051,9052,9053,9054,9055,9056,9057,
810269058,9059,9060,9061,9062,9063,9064,9065,9066,9067,9068,9069,9070,9071,9072,
810279073,9074,9075,9076,9077,9078,9079,9080,9081,9082,9083,9084,9085,9086,9087,
810289088,9089,9090,9091,9092,9093,9094,9095,9096,9097,9098,9099,9100,9101,9102,
810299103,9104,9105,9106,9107,9108,9109,9110,9111,9112,9113,9114,9115,9116,9117,
810309118,9119,9120,9121,9122,9123,9124,9125,9126,9127,9128,9129,9130,9131,9132,
810319133,9134,9135,9136,9137,9138,9139,9140,9141,9142,9143,9144,9145,9146,9147,
810329148,9149,9150,9151,9152,9153,9154,9155,9156,9157,9158,9159,9160,9161,9162,
810339163,9164,9165,9166,9167,9168,9169,9170,9171,9172,9173,9174,9175,9176,9177,
810349178,9179,9180,9181,9182,9183,9184,9185,9186,9187,9188,9189,9190,9191,9192,
810359193,9194,9195,9196,9197,9198,9199,9200,9201,9202,9203,9204,9205,9206,9207,
810369208,9209,9210,9211,9212,9213,9214,9215,9216,9217,9218,9219,9220,9221,9222,
810379223,9224,9225,9226,9227,9228,9229,9230,9231,9232,9233,9234,9235,9236,9237,
810389238,9239,9240,9241,9242,9243,9244,9245,9246,9247,9248,9249,9250,9251,9252,
810399253,9254,9255,9256,9257,9258,9259,9260,9261,9262,9263,9264,9265,9266,9267,
810409268,9269,9270,9271,9272,9273,9274,9275,9276,9277,9278,9279,9280,9281,9282,
810419283,9284,9285,9286,9287,9288,9289,9290,9291,9292,9293,9294,9295,9296,9297,
810429298,9299,9300,9301,9302,9303,9304,9305,9306,9307,9308,9309,9310,9311,9312,
810439313,9314,9315,9316,9317,9318,9319,9320,9321,9322,9323,9324,9325,9326,9327,
810449328,9329,9330,9331,9332,9333,9334,9335,9336,9337,9338,9339,9340,9341,9342,
810459343,9344,9345,9346,9347,9348,9349,9350,9351,9352,9353,9354,9355,9356,9357,
810469358,9359,9360,9361,9362,9363,9364,9365,9366,9367,9368,9369,9370,9371,9372,
810479373,9374,9375,9376,9377,9378,9379,9380,9381,9382,9383,9384,9385,9386,9387,
810489388,9389,9390,9391,9392,9393,9394,9395,9396,9397,9398,9399,9400,9401,9402,
810499403,9404,9405,9406,9407,9408,9409,9410,9411,9412,9413,9414,9415,9416,9417,
810509418,9419,9420,9421,9422,9423,9398,9399,9400,9401,9402,9403,9404,9405,9406,
810519407,9408,9409,9410,9411,9412,9413,9414,9415,9416,9417,9418,9419,9420,9421,
810529422,9423,9450,9451,9452,9453,9454,9455,9456,9457,9458,9459,9460,9461,9462,
810539463,9464,9465,9466,9467,9468,9469,9470,9471,9472,9473,9474,9475,9476,9477,
810549478,9479,9480,9481,9482,9483,9484,9485,9486,9487,9488,9489,9490,9491,9492,
810559493,9494,9495,9496,9497,9498,9499,9500,9501,9502,9503,9504,9505,9506,9507,
810569508,9509,9510,9511,9512,9513,9514,9515,9516,9517,9518,9519,9520,9521,9522,
810579523,9524,9525,9526,9527,9528,9529,9530,9531,9532,9533,9534,9535,9536,9537,
810589538,9539,9540,9541,9542,9543,9544,9545,9546,9547,9548,9549,9550,9551,9552,
810599553,9554,9555,9556,9557,9558,9559,9560,9561,9562,9563,9564,9565,9566,9567,
810609568,9569,9570,9571,9572,9573,9574,9575,9576,9577,9578,9579,9580,9581,9582,
810619583,9584,9585,9586,9587,9588,9589,9590,9591,9592,9593,9594,9595,9596,9597,
810629598,9599,9600,9601,9602,9603,9604,9605,9606,9607,9608,9609,9610,9611,9612,
810639613,9614,9615,9616,9617,9618,9619,9620,9621,9622,9623,9624,9625,9626,9627,
810649628,9629,9630,9631,9632,9633,9634,9635,9636,9637,9638,9639,9640,9641,9642,
810659643,9644,9645,9646,9647,9648,9649,9650,9651,9652,9653,9654,9655,9656,9657,
810669658,9659,9660,9661,9662,9663,9664,9665,9666,9667,9668,9669,9670,9671,9672,
810679673,9674,9675,9676,9677,9678,9679,9680,9681,9682,9683,9684,9685,9686,9687,
810689688,9689,9690,9691,9692,9693,9694,9695,9696,9697,9698,9699,9700,9701,9702,
810699703,9704,9705,9706,9707,9708,9709,9710,9711,9712,9713,9714,9715,9716,9717,
810709718,9719,9720,9721,9722,9723,9724,9725,9726,9727,9728,9729,9730,9731,9732,
810719733,9734,9735,9736,9737,9738,9739,9740,9741,9742,9743,9744,9745,9746,9747,
810729748,9749,9750,9751,9752,9753,9754,9755,9756,9757,9758,9759,9760,9761,9762,
810739763,9764,9765,9766,9767,9768,9769,9770,9771,9772,9773,9774,9775,9776,9777,
810749778,9779,9780,9781,9782,9783,9784,9785,9786,9787,9788,9789,9790,9791,9792,
810759793,9794,9795,9796,9797,9798,9799,9800,9801,9802,9803,9804,9805,9806,9807,
810769808,9809,9810,9811,9812,9813,9814,9815,9816,9817,9818,9819,9820,9821,9822,
810779823,9824,9825,9826,9827,9828,9829,9830,9831,9832,9833,9834,9835,9836,9837,
810789838,9839,9840,9841,9842,9843,9844,9845,9846,9847,9848,9849,9850,9851,9852,
810799853,9854,9855,9856,9857,9858,9859,9860,9861,9862,9863,9864,9865,9866,9867,
810809868,9869,9870,9871,9872,9873,9874,9875,9876,9877,9878,9879,9880,9881,9882,
810819883,9884,9885,9886,9887,9888,9889,9890,9891,9892,9893,9894,9895,9896,9897,
810829898,9899,9900,9901,9902,9903,9904,9905,9906,9907,9908,9909,9910,9911,9912,
810839913,9914,9915,9916,9917,9918,9919,9920,9921,9922,9923,9924,9925,9926,9927,
810849928,9929,9930,9931,9932,9933,9934,9935,9936,9937,9938,9939,9940,9941,9942,
810859943,9944,9945,9946,9947,9948,9949,9950,9951,9952,9953,9954,9955,9956,9957,
810869958,9959,9960,9961,9962,9963,9964,9965,9966,9967,9968,9969,9970,9971,9972,
810879973,9974,9975,9976,9977,9978,9979,9980,9981,9982,9983,9984,9985,9986,9987,
810889988,9989,9990,9991,9992,9993,9994,9995,9996,9997,9998,9999,10000,10001,
8108910002,10003,10004,10005,10006,10007,10008,10009,10010,10011,10012,10013,
8109010014,10015,10016,10017,10018,10019,10020,10021,10022,10023,10024,10025,
8109110026,10027,10028,10029,10030,10031,10032,10033,10034,10035,10036,10037,
8109210038,10039,10040,10041,10042,10043,10044,10045,10046,10047,10048,10049,
8109310050,10051,10052,10053,10054,10055,10056,10057,10058,10059,10060,10061,
8109410062,10063,10064,10065,10066,10067,10068,10069,10070,10071,10072,10073,
8109510074,10075,10076,10077,10078,10079,10080,10081,10082,10083,10084,10085,
8109610086,10087,10088,10089,10090,10091,10092,10093,10094,10095,10096,10097,
8109710098,10099,10100,10101,10102,10103,10104,10105,10106,10107,10108,10109,
8109810110,10111,10112,10113,10114,10115,10116,10117,10118,10119,10120,10121,
8109910122,10123,10124,10125,10126,10127,10128,10129,10130,10131,10132,10133,
8110010134,10135,10136,10137,10138,10139,10140,10141,10142,10143,10144,10145,
8110110146,10147,10148,10149,10150,10151,10152,10153,10154,10155,10156,10157,
8110210158,10159,10160,10161,10162,10163,10164,10165,10166,10167,10168,10169,
8110310170,10171,10172,10173,10174,10175,10176,10177,10178,10179,10180,10181,
8110410182,10183,10184,10185,10186,10187,10188,10189,10190,10191,10192,10193,
8110510194,10195,10196,10197,10198,10199,10200,10201,10202,10203,10204,10205,
8110610206,10207,10208,10209,10210,10211,10212,10213,10214,10215,10216,10217,
8110710218,10219,10220,10221,10222,10223,10224,10225,10226,10227,10228,10229,
8110810230,10231,10232,10233,10234,10235,10236,10237,10238,10239,10240,10241,
8110910242,10243,10244,10245,10246,10247,10248,10249,10250,10251,10252,10253,
8111010254,10255,10256,10257,10258,10259,10260,10261,10262,10263,10264,10265,
8111110266,10267,10268,10269,10270,10271,10272,10273,10274,10275,10276,10277,
8111210278,10279,10280,10281,10282,10283,10284,10285,10286,10287,10288,10289,
8111310290,10291,10292,10293,10294,10295,10296,10297,10298,10299,10300,10301,
8111410302,10303,10304,10305,10306,10307,10308,10309,10310,10311,10312,10313,
8111510314,10315,10316,10317,10318,10319,10320,10321,10322,10323,10324,10325,
8111610326,10327,10328,10329,10330,10331,10332,10333,10334,10335,10336,10337,
8111710338,10339,10340,10341,10342,10343,10344,10345,10346,10347,10348,10349,
8111810350,10351,10352,10353,10354,10355,10356,10357,10358,10359,10360,10361,
8111910362,10363,10364,10365,10366,10367,10368,10369,10370,10371,10372,10373,
8112010374,10375,10376,10377,10378,10379,10380,10381,10382,10383,10384,10385,
8112110386,10387,10388,10389,10390,10391,10392,10393,10394,10395,10396,10397,
8112210398,10399,10400,10401,10402,10403,10404,10405,10406,10407,10408,10409,
8112310410,10411,10412,10413,10414,10415,10416,10417,10418,10419,10420,10421,
8112410422,10423,10424,10425,10426,10427,10428,10429,10430,10431,10432,10433,
8112510434,10435,10436,10437,10438,10439,10440,10441,10442,10443,10444,10445,
8112610446,10447,10448,10449,10450,10451,10452,10453,10454,10455,10456,10457,
8112710458,10459,10460,10461,10462,10463,10464,10465,10466,10467,10468,10469,
8112810470,10471,10472,10473,10474,10475,10476,10477,10478,10479,10480,10481,
8112910482,10483,10484,10485,10486,10487,10488,10489,10490,10491,10492,10493,
8113010494,10495,10496,10497,10498,10499,10500,10501,10502,10503,10504,10505,
8113110506,10507,10508,10509,10510,10511,10512,10513,10514,10515,10516,10517,
8113210518,10519,10520,10521,10522,10523,10524,10525,10526,10527,10528,10529,
8113310530,10531,10532,10533,10534,10535,10536,10537,10538,10539,10540,10541,
8113410542,10543,10544,10545,10546,10547,10548,10549,10550,10551,10552,10553,
8113510554,10555,10556,10557,10558,10559,10560,10561,10562,10563,10564,10565,
8113610566,10567,10568,10569,10570,10571,10572,10573,10574,10575,10576,10577,
8113710578,10579,10580,10581,10582,10583,10584,10585,10586,10587,10588,10589,
8113810590,10591,10592,10593,10594,10595,10596,10597,10598,10599,10600,10601,
8113910602,10603,10604,10605,10606,10607,10608,10609,10610,10611,10612,10613,
8114010614,10615,10616,10617,10618,10619,10620,10621,10622,10623,10624,10625,
8114110626,10627,10628,10629,10630,10631,10632,10633,10634,10635,10636,10637,
8114210638,10639,10640,10641,10642,10643,10644,10645,10646,10647,10648,10649,
8114310650,10651,10652,10653,10654,10655,10656,10657,10658,10659,10660,10661,
8114410662,10663,10664,10665,10666,10667,10668,10669,10670,10671,10672,10673,
8114510674,10675,10676,10677,10678,10679,10680,10681,10682,10683,10684,10685,
8114610686,10687,10688,10689,10690,10691,10692,10693,10694,10695,10696,10697,
8114710698,10699,10700,10701,10702,10703,10704,10705,10706,10707,10708,10709,
8114810710,10711,10712,10713,10714,10715,10716,10717,10718,10719,10720,10721,
8114910722,10723,10724,10725,10726,10727,10728,10729,10730,10731,10732,10733,
8115010734,10735,10736,10737,10738,10739,10740,10741,10742,10743,10744,10745,
8115110746,10747,10748,10749,10750,10751,10752,10753,10754,10755,10756,10757,
8115210758,10759,10760,10761,10762,10763,10764,10765,10766,10767,10768,10769,
8115310770,10771,10772,10773,10774,10775,10776,10777,10778,10779,10780,10781,
8115410782,10783,10784,10785,10786,10787,10788,10789,10790,10791,10792,10793,
8115510794,10795,10796,10797,10798,10799,10800,10801,10802,10803,10804,10805,
8115610806,10807,10808,10809,10810,10811,10812,10813,10814,10815,10816,10817,
8115710818,10819,10820,10821,10822,10823,10824,10825,10826,10827,10828,10829,
8115810830,10831,10832,10833,10834,10835,10836,10837,10838,10839,10840,10841,
8115910842,10843,10844,10845,10846,10847,10848,10849,10850,10851,10852,10853,
8116010854,10855,10856,10857,10858,10859,10860,10861,10862,10863,10864,10865,
8116110866,10867,10868,10869,10870,10871,10872,10873,10874,10875,10876,10877,
8116210878,10879,10880,10881,10882,10883,10884,10885,10886,10887,10888,10889,
8116310890,10891,10892,10893,10894,10895,10896,10897,10898,10899,10900,10901,
8116410902,10903,10904,10905,10906,10907,10908,10909,10910,10911,10912,10913,
8116510914,10915,10916,10917,10918,10919,10920,10921,10922,10923,10924,10925,
8116610926,10927,10928,10929,10930,10931,10932,10933,10934,10935,10936,10937,
8116710938,10939,10940,10941,10942,10943,10944,10945,10946,10947,10948,10949,
8116810950,10951,10952,10953,10954,10955,10956,10957,10958,10959,10960,10961,
8116910962,10963,10964,10965,10966,10967,10968,10969,10970,10971,10972,10973,
8117010974,10975,10976,10977,10978,10979,10980,10981,10982,10983,10984,10985,
8117110986,10987,10988,10989,10990,10991,10992,10993,10994,10995,10996,10997,
8117210998,10999,11000,11001,11002,11003,11004,11005,11006,11007,11008,11009,
8117311010,11011,11012,11013,11014,11015,11016,11017,11018,11019,11020,11021,
8117411022,11023,11024,11025,11026,11027,11028,11029,11030,11031,11032,11033,
8117511034,11035,11036,11037,11038,11039,11040,11041,11042,11043,11044,11045,
8117611046,11047,11048,11049,11050,11051,11052,11053,11054,11055,11056,11057,
8117711058,11059,11060,11061,11062,11063,11064,11065,11066,11067,11068,11069,
8117811070,11071,11072,11073,11074,11075,11076,11077,11078,11079,11080,11081,
8117911082,11083,11084,11085,11086,11087,11088,11089,11090,11091,11092,11093,
8118011094,11095,11096,11097,11098,11099,11100,11101,11102,11103,11104,11105,
8118111106,11107,11108,11109,11110,11111,11112,11113,11114,11115,11116,11117,
8118211118,11119,11120,11121,11122,11123,11124,11125,11126,11127,11128,11129,
8118311130,11131,11132,11133,11134,11135,11136,11137,11138,11139,11140,11141,
8118411142,11143,11144,11145,11146,11147,11148,11149,11150,11151,11152,11153,
8118511154,11155,11156,11157,11158,11159,11160,11161,11162,11163,11164,11165,
8118611166,11167,11168,11169,11170,11171,11172,11173,11174,11175,11176,11177,
8118711178,11179,11180,11181,11182,11183,11184,11185,11186,11187,11188,11189,
8118811190,11191,11192,11193,11194,11195,11196,11197,11198,11199,11200,11201,
8118911202,11203,11204,11205,11206,11207,11208,11209,11210,11211,11212,11213,
8119011214,11215,11216,11217,11218,11219,11220,11221,11222,11223,11224,11225,
8119111226,11227,11228,11229,11230,11231,11232,11233,11234,11235,11236,11237,
8119211238,11239,11240,11241,11242,11243,11244,11245,11246,11247,11248,11249,
8119311250,11251,11252,11253,11254,11255,11256,11257,11258,11259,11260,11261,
8119411262,11263,11264,11265,11266,11267,11268,11269,11270,11271,11272,11273,
8119511274,11275,11276,11277,11278,11279,11280,11281,11282,11283,11284,11285,
8119611286,11287,11288,11289,11290,11291,11292,11293,11294,11295,11296,11297,
8119711298,11299,11300,11301,11302,11303,11304,11305,11306,11307,11308,11309,
8119811310,11311,11264,11265,11266,11267,11268,11269,11270,11271,11272,11273,
8119911274,11275,11276,11277,11278,11279,11280,11281,11282,11283,11284,11285,
8120011286,11287,11288,11289,11290,11291,11292,11293,11294,11295,11296,11297,
8120111298,11299,11300,11301,11302,11303,11304,11305,11306,11307,11308,11309,
8120211310,11359,11360,11360,11362,11363,11364,570,574,11367,11367,11369,11369,
8120311371,11371,11373,11374,11375,11376,11377,11378,11378,11380,11381,11381,
8120411383,11384,11385,11386,11387,11388,11389,11390,11391,11392,11392,11394,
8120511394,11396,11396,11398,11398,11400,11400,11402,11402,11404,11404,11406,
8120611406,11408,11408,11410,11410,11412,11412,11414,11414,11416,11416,11418,
8120711418,11420,11420,11422,11422,11424,11424,11426,11426,11428,11428,11430,
8120811430,11432,11432,11434,11434,11436,11436,11438,11438,11440,11440,11442,
8120911442,11444,11444,11446,11446,11448,11448,11450,11450,11452,11452,11454,
8121011454,11456,11456,11458,11458,11460,11460,11462,11462,11464,11464,11466,
8121111466,11468,11468,11470,11470,11472,11472,11474,11474,11476,11476,11478,
8121211478,11480,11480,11482,11482,11484,11484,11486,11486,11488,11488,11490,
8121311490,11492,11493,11494,11495,11496,11497,11498,11499,11499,11501,11501,
8121411503,11504,11505,11506,11507,11508,11509,11510,11511,11512,11513,11514,
8121511515,11516,11517,11518,11519,4256,4257,4258,4259,4260,4261,4262,4263,4264,
812164265,4266,4267,4268,4269,4270,4271,4272,4273,4274,4275,4276,4277,4278,4279,
812174280,4281,4282,4283,4284,4285,4286,4287,4288,4289,4290,4291,4292,4293,
8121811558,11559,11560,11561,11562,11563,11564,11565,11566,11567,11568,11569,
8121911570,11571,11572,11573,11574,11575,11576,11577,11578,11579,11580,11581,
8122011582,11583,11584,11585,11586,11587,11588,11589,11590,11591,11592,11593,
8122111594,11595,11596,11597,11598,11599,11600,11601,11602,11603,11604,11605,
8122211606,11607,11608,11609,11610,11611,11612,11613,11614,11615,11616,11617,
8122311618,11619,11620,11621,11622,11623,11624,11625,11626,11627,11628,11629,
8122411630,11631,11632,11633,11634,11635,11636,11637,11638,11639,11640,11641,
8122511642,11643,11644,11645,11646,11647,11648,11649,11650,11651,11652,11653,
8122611654,11655,11656,11657,11658,11659,11660,11661,11662,11663,11664,11665,
8122711666,11667,11668,11669,11670,11671,11672,11673,11674,11675,11676,11677,
8122811678,11679,11680,11681,11682,11683,11684,11685,11686,11687,11688,11689,
8122911690,11691,11692,11693,11694,11695,11696,11697,11698,11699,11700,11701,
8123011702,11703,11704,11705,11706,11707,11708,11709,11710,11711,11712,11713,
8123111714,11715,11716,11717,11718,11719,11720,11721,11722,11723,11724,11725,
8123211726,11727,11728,11729,11730,11731,11732,11733,11734,11735,11736,11737,
8123311738,11739,11740,11741,11742,11743,11744,11745,11746,11747,11748,11749,
8123411750,11751,11752,11753,11754,11755,11756,11757,11758,11759,11760,11761,
8123511762,11763,11764,11765,11766,11767,11768,11769,11770,11771,11772,11773,
8123611774,11775,11776,11777,11778,11779,11780,11781,11782,11783,11784,11785,
8123711786,11787,11788,11789,11790,11791,11792,11793,11794,11795,11796,11797,
8123811798,11799,11800,11801,11802,11803,11804,11805,11806,11807,11808,11809,
8123911810,11811,11812,11813,11814,11815,11816,11817,11818,11819,11820,11821,
8124011822,11823,11824,11825,11826,11827,11828,11829,11830,11831,11832,11833,
8124111834,11835,11836,11837,11838,11839,11840,11841,11842,11843,11844,11845,
8124211846,11847,11848,11849,11850,11851,11852,11853,11854,11855,11856,11857,
8124311858,11859,11860,11861,11862,11863,11864,11865,11866,11867,11868,11869,
8124411870,11871,11872,11873,11874,11875,11876,11877,11878,11879,11880,11881,
8124511882,11883,11884,11885,11886,11887,11888,11889,11890,11891,11892,11893,
8124611894,11895,11896,11897,11898,11899,11900,11901,11902,11903,11904,11905,
8124711906,11907,11908,11909,11910,11911,11912,11913,11914,11915,11916,11917,
8124811918,11919,11920,11921,11922,11923,11924,11925,11926,11927,11928,11929,
8124911930,11931,11932,11933,11934,11935,11936,11937,11938,11939,11940,11941,
8125011942,11943,11944,11945,11946,11947,11948,11949,11950,11951,11952,11953,
8125111954,11955,11956,11957,11958,11959,11960,11961,11962,11963,11964,11965,
8125211966,11967,11968,11969,11970,11971,11972,11973,11974,11975,11976,11977,
8125311978,11979,11980,11981,11982,11983,11984,11985,11986,11987,11988,11989,
8125411990,11991,11992,11993,11994,11995,11996,11997,11998,11999,12000,12001,
8125512002,12003,12004,12005,12006,12007,12008,12009,12010,12011,12012,12013,
8125612014,12015,12016,12017,12018,12019,12020,12021,12022,12023,12024,12025,
8125712026,12027,12028,12029,12030,12031,12032,12033,12034,12035,12036,12037,
8125812038,12039,12040,12041,12042,12043,12044,12045,12046,12047,12048,12049,
8125912050,12051,12052,12053,12054,12055,12056,12057,12058,12059,12060,12061,
8126012062,12063,12064,12065,12066,12067,12068,12069,12070,12071,12072,12073,
8126112074,12075,12076,12077,12078,12079,12080,12081,12082,12083,12084,12085,
8126212086,12087,12088,12089,12090,12091,12092,12093,12094,12095,12096,12097,
8126312098,12099,12100,12101,12102,12103,12104,12105,12106,12107,12108,12109,
8126412110,12111,12112,12113,12114,12115,12116,12117,12118,12119,12120,12121,
8126512122,12123,12124,12125,12126,12127,12128,12129,12130,12131,12132,12133,
8126612134,12135,12136,12137,12138,12139,12140,12141,12142,12143,12144,12145,
8126712146,12147,12148,12149,12150,12151,12152,12153,12154,12155,12156,12157,
8126812158,12159,12160,12161,12162,12163,12164,12165,12166,12167,12168,12169,
8126912170,12171,12172,12173,12174,12175,12176,12177,12178,12179,12180,12181,
8127012182,12183,12184,12185,12186,12187,12188,12189,12190,12191,12192,12193,
8127112194,12195,12196,12197,12198,12199,12200,12201,12202,12203,12204,12205,
8127212206,12207,12208,12209,12210,12211,12212,12213,12214,12215,12216,12217,
8127312218,12219,12220,12221,12222,12223,12224,12225,12226,12227,12228,12229,
8127412230,12231,12232,12233,12234,12235,12236,12237,12238,12239,12240,12241,
8127512242,12243,12244,12245,12246,12247,12248,12249,12250,12251,12252,12253,
8127612254,12255,12256,12257,12258,12259,12260,12261,12262,12263,12264,12265,
8127712266,12267,12268,12269,12270,12271,12272,12273,12274,12275,12276,12277,
8127812278,12279,12280,12281,12282,12283,12284,12285,12286,12287,12288,12289,
8127912290,12291,12292,12293,12294,12295,12296,12297,12298,12299,12300,12301,
8128012302,12303,12304,12305,12306,12307,12308,12309,12310,12311,12312,12313,
8128112314,12315,12316,12317,12318,12319,12320,12321,12322,12323,12324,12325,
8128212326,12327,12328,12329,12330,12331,12332,12333,12334,12335,12336,12337,
8128312338,12339,12340,12341,12342,12343,12344,12345,12346,12347,12348,12349,
8128412350,12351,12352,12353,12354,12355,12356,12357,12358,12359,12360,12361,
8128512362,12363,12364,12365,12366,12367,12368,12369,12370,12371,12372,12373,
8128612374,12375,12376,12377,12378,12379,12380,12381,12382,12383,12384,12385,
8128712386,12387,12388,12389,12390,12391,12392,12393,12394,12395,12396,12397,
8128812398,12399,12400,12401,12402,12403,12404,12405,12406,12407,12408,12409,
8128912410,12411,12412,12413,12414,12415,12416,12417,12418,12419,12420,12421,
8129012422,12423,12424,12425,12426,12427,12428,12429,12430,12431,12432,12433,
8129112434,12435,12436,12437,12438,12439,12440,12441,12442,12443,12444,12445,
8129212446,12447,12448,12449,12450,12451,12452,12453,12454,12455,12456,12457,
8129312458,12459,12460,12461,12462,12463,12464,12465,12466,12467,12468,12469,
8129412470,12471,12472,12473,12474,12475,12476,12477,12478,12479,12480,12481,
8129512482,12483,12484,12485,12486,12487,12488,12489,12490,12491,12492,12493,
8129612494,12495,12496,12497,12498,12499,12500,12501,12502,12503,12504,12505,
8129712506,12507,12508,12509,12510,12511,12512,12513,12514,12515,12516,12517,
8129812518,12519,12520,12521,12522,12523,12524,12525,12526,12527,12528,12529,
8129912530,12531,12532,12533,12534,12535,12536,12537,12538,12539,12540,12541,
8130012542,12543,12544,12545,12546,12547,12548,12549,12550,12551,12552,12553,
8130112554,12555,12556,12557,12558,12559,12560,12561,12562,12563,12564,12565,
8130212566,12567,12568,12569,12570,12571,12572,12573,12574,12575,12576,12577,
8130312578,12579,12580,12581,12582,12583,12584,12585,12586,12587,12588,12589,
8130412590,12591,12592,12593,12594,12595,12596,12597,12598,12599,12600,12601,
8130512602,12603,12604,12605,12606,12607,12608,12609,12610,12611,12612,12613,
8130612614,12615,12616,12617,12618,12619,12620,12621,12622,12623,12624,12625,
8130712626,12627,12628,12629,12630,12631,12632,12633,12634,12635,12636,12637,
8130812638,12639,12640,12641,12642,12643,12644,12645,12646,12647,12648,12649,
8130912650,12651,12652,12653,12654,12655,12656,12657,12658,12659,12660,12661,
8131012662,12663,12664,12665,12666,12667,12668,12669,12670,12671,12672,12673,
8131112674,12675,12676,12677,12678,12679,12680,12681,12682,12683,12684,12685,
8131212686,12687,12688,12689,12690,12691,12692,12693,12694,12695,12696,12697,
8131312698,12699,12700,12701,12702,12703,12704,12705,12706,12707,12708,12709,
8131412710,12711,12712,12713,12714,12715,12716,12717,12718,12719,12720,12721,
8131512722,12723,12724,12725,12726,12727,12728,12729,12730,12731,12732,12733,
8131612734,12735,12736,12737,12738,12739,12740,12741,12742,12743,12744,12745,
8131712746,12747,12748,12749,12750,12751,12752,12753,12754,12755,12756,12757,
8131812758,12759,12760,12761,12762,12763,12764,12765,12766,12767,12768,12769,
8131912770,12771,12772,12773,12774,12775,12776,12777,12778,12779,12780,12781,
8132012782,12783,12784,12785,12786,12787,12788,12789,12790,12791,12792,12793,
8132112794,12795,12796,12797,12798,12799,12800,12801,12802,12803,12804,12805,
8132212806,12807,12808,12809,12810,12811,12812,12813,12814,12815,12816,12817,
8132312818,12819,12820,12821,12822,12823,12824,12825,12826,12827,12828,12829,
8132412830,12831,12832,12833,12834,12835,12836,12837,12838,12839,12840,12841,
8132512842,12843,12844,12845,12846,12847,12848,12849,12850,12851,12852,12853,
8132612854,12855,12856,12857,12858,12859,12860,12861,12862,12863,12864,12865,
8132712866,12867,12868,12869,12870,12871,12872,12873,12874,12875,12876,12877,
8132812878,12879,12880,12881,12882,12883,12884,12885,12886,12887,12888,12889,
8132912890,12891,12892,12893,12894,12895,12896,12897,12898,12899,12900,12901,
8133012902,12903,12904,12905,12906,12907,12908,12909,12910,12911,12912,12913,
8133112914,12915,12916,12917,12918,12919,12920,12921,12922,12923,12924,12925,
8133212926,12927,12928,12929,12930,12931,12932,12933,12934,12935,12936,12937,
8133312938,12939,12940,12941,12942,12943,12944,12945,12946,12947,12948,12949,
8133412950,12951,12952,12953,12954,12955,12956,12957,12958,12959,12960,12961,
8133512962,12963,12964,12965,12966,12967,12968,12969,12970,12971,12972,12973,
8133612974,12975,12976,12977,12978,12979,12980,12981,12982,12983,12984,12985,
8133712986,12987,12988,12989,12990,12991,12992,12993,12994,12995,12996,12997,
8133812998,12999,13000,13001,13002,13003,13004,13005,13006,13007,13008,13009,
8133913010,13011,13012,13013,13014,13015,13016,13017,13018,13019,13020,13021,
8134013022,13023,13024,13025,13026,13027,13028,13029,13030,13031,13032,13033,
8134113034,13035,13036,13037,13038,13039,13040,13041,13042,13043,13044,13045,
8134213046,13047,13048,13049,13050,13051,13052,13053,13054,13055,13056,13057,
8134313058,13059,13060,13061,13062,13063,13064,13065,13066,13067,13068,13069,
8134413070,13071,13072,13073,13074,13075,13076,13077,13078,13079,13080,13081,
8134513082,13083,13084,13085,13086,13087,13088,13089,13090,13091,13092,13093,
8134613094,13095,13096,13097,13098,13099,13100,13101,13102,13103,13104,13105,
8134713106,13107,13108,13109,13110,13111,13112,13113,13114,13115,13116,13117,
8134813118,13119,13120,13121,13122,13123,13124,13125,13126,13127,13128,13129,
8134913130,13131,13132,13133,13134,13135,13136,13137,13138,13139,13140,13141,
8135013142,13143,13144,13145,13146,13147,13148,13149,13150,13151,13152,13153,
8135113154,13155,13156,13157,13158,13159,13160,13161,13162,13163,13164,13165,
8135213166,13167,13168,13169,13170,13171,13172,13173,13174,13175,13176,13177,
8135313178,13179,13180,13181,13182,13183,13184,13185,13186,13187,13188,13189,
8135413190,13191,13192,13193,13194,13195,13196,13197,13198,13199,13200,13201,
8135513202,13203,13204,13205,13206,13207,13208,13209,13210,13211,13212,13213,
8135613214,13215,13216,13217,13218,13219,13220,13221,13222,13223,13224,13225,
8135713226,13227,13228,13229,13230,13231,13232,13233,13234,13235,13236,13237,
8135813238,13239,13240,13241,13242,13243,13244,13245,13246,13247,13248,13249,
8135913250,13251,13252,13253,13254,13255,13256,13257,13258,13259,13260,13261,
8136013262,13263,13264,13265,13266,13267,13268,13269,13270,13271,13272,13273,
8136113274,13275,13276,13277,13278,13279,13280,13281,13282,13283,13284,13285,
8136213286,13287,13288,13289,13290,13291,13292,13293,13294,13295,13296,13297,
8136313298,13299,13300,13301,13302,13303,13304,13305,13306,13307,13308,13309,
8136413310,13311,13312,13313,13314,13315,13316,13317,13318,13319,13320,13321,
8136513322,13323,13324,13325,13326,13327,13328,13329,13330,13331,13332,13333,
8136613334,13335,13336,13337,13338,13339,13340,13341,13342,13343,13344,13345,
8136713346,13347,13348,13349,13350,13351,13352,13353,13354,13355,13356,13357,
8136813358,13359,13360,13361,13362,13363,13364,13365,13366,13367,13368,13369,
8136913370,13371,13372,13373,13374,13375,13376,13377,13378,13379,13380,13381,
8137013382,13383,13384,13385,13386,13387,13388,13389,13390,13391,13392,13393,
8137113394,13395,13396,13397,13398,13399,13400,13401,13402,13403,13404,13405,
8137213406,13407,13408,13409,13410,13411,13412,13413,13414,13415,13416,13417,
8137313418,13419,13420,13421,13422,13423,13424,13425,13426,13427,13428,13429,
8137413430,13431,13432,13433,13434,13435,13436,13437,13438,13439,13440,13441,
8137513442,13443,13444,13445,13446,13447,13448,13449,13450,13451,13452,13453,
8137613454,13455,13456,13457,13458,13459,13460,13461,13462,13463,13464,13465,
8137713466,13467,13468,13469,13470,13471,13472,13473,13474,13475,13476,13477,
8137813478,13479,13480,13481,13482,13483,13484,13485,13486,13487,13488,13489,
8137913490,13491,13492,13493,13494,13495,13496,13497,13498,13499,13500,13501,
8138013502,13503,13504,13505,13506,13507,13508,13509,13510,13511,13512,13513,
8138113514,13515,13516,13517,13518,13519,13520,13521,13522,13523,13524,13525,
8138213526,13527,13528,13529,13530,13531,13532,13533,13534,13535,13536,13537,
8138313538,13539,13540,13541,13542,13543,13544,13545,13546,13547,13548,13549,
8138413550,13551,13552,13553,13554,13555,13556,13557,13558,13559,13560,13561,
8138513562,13563,13564,13565,13566,13567,13568,13569,13570,13571,13572,13573,
8138613574,13575,13576,13577,13578,13579,13580,13581,13582,13583,13584,13585,
8138713586,13587,13588,13589,13590,13591,13592,13593,13594,13595,13596,13597,
8138813598,13599,13600,13601,13602,13603,13604,13605,13606,13607,13608,13609,
8138913610,13611,13612,13613,13614,13615,13616,13617,13618,13619,13620,13621,
8139013622,13623,13624,13625,13626,13627,13628,13629,13630,13631,13632,13633,
8139113634,13635,13636,13637,13638,13639,13640,13641,13642,13643,13644,13645,
8139213646,13647,13648,13649,13650,13651,13652,13653,13654,13655,13656,13657,
8139313658,13659,13660,13661,13662,13663,13664,13665,13666,13667,13668,13669,
8139413670,13671,13672,13673,13674,13675,13676,13677,13678,13679,13680,13681,
8139513682,13683,13684,13685,13686,13687,13688,13689,13690,13691,13692,13693,
8139613694,13695,13696,13697,13698,13699,13700,13701,13702,13703,13704,13705,
8139713706,13707,13708,13709,13710,13711,13712,13713,13714,13715,13716,13717,
8139813718,13719,13720,13721,13722,13723,13724,13725,13726,13727,13728,13729,
8139913730,13731,13732,13733,13734,13735,13736,13737,13738,13739,13740,13741,
8140013742,13743,13744,13745,13746,13747,13748,13749,13750,13751,13752,13753,
8140113754,13755,13756,13757,13758,13759,13760,13761,13762,13763,13764,13765,
8140213766,13767,13768,13769,13770,13771,13772,13773,13774,13775,13776,13777,
8140313778,13779,13780,13781,13782,13783,13784,13785,13786,13787,13788,13789,
8140413790,13791,13792,13793,13794,13795,13796,13797,13798,13799,13800,13801,
8140513802,13803,13804,13805,13806,13807,13808,13809,13810,13811,13812,13813,
8140613814,13815,13816,13817,13818,13819,13820,13821,13822,13823,13824,13825,
8140713826,13827,13828,13829,13830,13831,13832,13833,13834,13835,13836,13837,
8140813838,13839,13840,13841,13842,13843,13844,13845,13846,13847,13848,13849,
8140913850,13851,13852,13853,13854,13855,13856,13857,13858,13859,13860,13861,
8141013862,13863,13864,13865,13866,13867,13868,13869,13870,13871,13872,13873,
8141113874,13875,13876,13877,13878,13879,13880,13881,13882,13883,13884,13885,
8141213886,13887,13888,13889,13890,13891,13892,13893,13894,13895,13896,13897,
8141313898,13899,13900,13901,13902,13903,13904,13905,13906,13907,13908,13909,
8141413910,13911,13912,13913,13914,13915,13916,13917,13918,13919,13920,13921,
8141513922,13923,13924,13925,13926,13927,13928,13929,13930,13931,13932,13933,
8141613934,13935,13936,13937,13938,13939,13940,13941,13942,13943,13944,13945,
8141713946,13947,13948,13949,13950,13951,13952,13953,13954,13955,13956,13957,
8141813958,13959,13960,13961,13962,13963,13964,13965,13966,13967,13968,13969,
8141913970,13971,13972,13973,13974,13975,13976,13977,13978,13979,13980,13981,
8142013982,13983,13984,13985,13986,13987,13988,13989,13990,13991,13992,13993,
8142113994,13995,13996,13997,13998,13999,14000,14001,14002,14003,14004,14005,
8142214006,14007,14008,14009,14010,14011,14012,14013,14014,14015,14016,14017,
8142314018,14019,14020,14021,14022,14023,14024,14025,14026,14027,14028,14029,
8142414030,14031,14032,14033,14034,14035,14036,14037,14038,14039,14040,14041,
8142514042,14043,14044,14045,14046,14047,14048,14049,14050,14051,14052,14053,
8142614054,14055,14056,14057,14058,14059,14060,14061,14062,14063,14064,14065,
8142714066,14067,14068,14069,14070,14071,14072,14073,14074,14075,14076,14077,
8142814078,14079,14080,14081,14082,14083,14084,14085,14086,14087,14088,14089,
8142914090,14091,14092,14093,14094,14095,14096,14097,14098,14099,14100,14101,
8143014102,14103,14104,14105,14106,14107,14108,14109,14110,14111,14112,14113,
8143114114,14115,14116,14117,14118,14119,14120,14121,14122,14123,14124,14125,
8143214126,14127,14128,14129,14130,14131,14132,14133,14134,14135,14136,14137,
8143314138,14139,14140,14141,14142,14143,14144,14145,14146,14147,14148,14149,
8143414150,14151,14152,14153,14154,14155,14156,14157,14158,14159,14160,14161,
8143514162,14163,14164,14165,14166,14167,14168,14169,14170,14171,14172,14173,
8143614174,14175,14176,14177,14178,14179,14180,14181,14182,14183,14184,14185,
8143714186,14187,14188,14189,14190,14191,14192,14193,14194,14195,14196,14197,
8143814198,14199,14200,14201,14202,14203,14204,14205,14206,14207,14208,14209,
8143914210,14211,14212,14213,14214,14215,14216,14217,14218,14219,14220,14221,
8144014222,14223,14224,14225,14226,14227,14228,14229,14230,14231,14232,14233,
8144114234,14235,14236,14237,14238,14239,14240,14241,14242,14243,14244,14245,
8144214246,14247,14248,14249,14250,14251,14252,14253,14254,14255,14256,14257,
8144314258,14259,14260,14261,14262,14263,14264,14265,14266,14267,14268,14269,
8144414270,14271,14272,14273,14274,14275,14276,14277,14278,14279,14280,14281,
8144514282,14283,14284,14285,14286,14287,14288,14289,14290,14291,14292,14293,
8144614294,14295,14296,14297,14298,14299,14300,14301,14302,14303,14304,14305,
8144714306,14307,14308,14309,14310,14311,14312,14313,14314,14315,14316,14317,
8144814318,14319,14320,14321,14322,14323,14324,14325,14326,14327,14328,14329,
8144914330,14331,14332,14333,14334,14335,14336,14337,14338,14339,14340,14341,
8145014342,14343,14344,14345,14346,14347,14348,14349,14350,14351,14352,14353,
8145114354,14355,14356,14357,14358,14359,14360,14361,14362,14363,14364,14365,
8145214366,14367,14368,14369,14370,14371,14372,14373,14374,14375,14376,14377,
8145314378,14379,14380,14381,14382,14383,14384,14385,14386,14387,14388,14389,
8145414390,14391,14392,14393,14394,14395,14396,14397,14398,14399,14400,14401,
8145514402,14403,14404,14405,14406,14407,14408,14409,14410,14411,14412,14413,
8145614414,14415,14416,14417,14418,14419,14420,14421,14422,14423,14424,14425,
8145714426,14427,14428,14429,14430,14431,14432,14433,14434,14435,14436,14437,
8145814438,14439,14440,14441,14442,14443,14444,14445,14446,14447,14448,14449,
8145914450,14451,14452,14453,14454,14455,14456,14457,14458,14459,14460,14461,
8146014462,14463,14464,14465,14466,14467,14468,14469,14470,14471,14472,14473,
8146114474,14475,14476,14477,14478,14479,14480,14481,14482,14483,14484,14485,
8146214486,14487,14488,14489,14490,14491,14492,14493,14494,14495,14496,14497,
8146314498,14499,14500,14501,14502,14503,14504,14505,14506,14507,14508,14509,
8146414510,14511,14512,14513,14514,14515,14516,14517,14518,14519,14520,14521,
8146514522,14523,14524,14525,14526,14527,14528,14529,14530,14531,14532,14533,
8146614534,14535,14536,14537,14538,14539,14540,14541,14542,14543,14544,14545,
8146714546,14547,14548,14549,14550,14551,14552,14553,14554,14555,14556,14557,
8146814558,14559,14560,14561,14562,14563,14564,14565,14566,14567,14568,14569,
8146914570,14571,14572,14573,14574,14575,14576,14577,14578,14579,14580,14581,
8147014582,14583,14584,14585,14586,14587,14588,14589,14590,14591,14592,14593,
8147114594,14595,14596,14597,14598,14599,14600,14601,14602,14603,14604,14605,
8147214606,14607,14608,14609,14610,14611,14612,14613,14614,14615,14616,14617,
8147314618,14619,14620,14621,14622,14623,14624,14625,14626,14627,14628,14629,
8147414630,14631,14632,14633,14634,14635,14636,14637,14638,14639,14640,14641,
8147514642,14643,14644,14645,14646,14647,14648,14649,14650,14651,14652,14653,
8147614654,14655,14656,14657,14658,14659,14660,14661,14662,14663,14664,14665,
8147714666,14667,14668,14669,14670,14671,14672,14673,14674,14675,14676,14677,
8147814678,14679,14680,14681,14682,14683,14684,14685,14686,14687,14688,14689,
8147914690,14691,14692,14693,14694,14695,14696,14697,14698,14699,14700,14701,
8148014702,14703,14704,14705,14706,14707,14708,14709,14710,14711,14712,14713,
8148114714,14715,14716,14717,14718,14719,14720,14721,14722,14723,14724,14725,
8148214726,14727,14728,14729,14730,14731,14732,14733,14734,14735,14736,14737,
8148314738,14739,14740,14741,14742,14743,14744,14745,14746,14747,14748,14749,
8148414750,14751,14752,14753,14754,14755,14756,14757,14758,14759,14760,14761,
8148514762,14763,14764,14765,14766,14767,14768,14769,14770,14771,14772,14773,
8148614774,14775,14776,14777,14778,14779,14780,14781,14782,14783,14784,14785,
8148714786,14787,14788,14789,14790,14791,14792,14793,14794,14795,14796,14797,
8148814798,14799,14800,14801,14802,14803,14804,14805,14806,14807,14808,14809,
8148914810,14811,14812,14813,14814,14815,14816,14817,14818,14819,14820,14821,
8149014822,14823,14824,14825,14826,14827,14828,14829,14830,14831,14832,14833,
8149114834,14835,14836,14837,14838,14839,14840,14841,14842,14843,14844,14845,
8149214846,14847,14848,14849,14850,14851,14852,14853,14854,14855,14856,14857,
8149314858,14859,14860,14861,14862,14863,14864,14865,14866,14867,14868,14869,
8149414870,14871,14872,14873,14874,14875,14876,14877,14878,14879,14880,14881,
8149514882,14883,14884,14885,14886,14887,14888,14889,14890,14891,14892,14893,
8149614894,14895,14896,14897,14898,14899,14900,14901,14902,14903,14904,14905,
8149714906,14907,14908,14909,14910,14911,14912,14913,14914,14915,14916,14917,
8149814918,14919,14920,14921,14922,14923,14924,14925,14926,14927,14928,14929,
8149914930,14931,14932,14933,14934,14935,14936,14937,14938,14939,14940,14941,
8150014942,14943,14944,14945,14946,14947,14948,14949,14950,14951,14952,14953,
8150114954,14955,14956,14957,14958,14959,14960,14961,14962,14963,14964,14965,
8150214966,14967,14968,14969,14970,14971,14972,14973,14974,14975,14976,14977,
8150314978,14979,14980,14981,14982,14983,14984,14985,14986,14987,14988,14989,
8150414990,14991,14992,14993,14994,14995,14996,14997,14998,14999,15000,15001,
8150515002,15003,15004,15005,15006,15007,15008,15009,15010,15011,15012,15013,
8150615014,15015,15016,15017,15018,15019,15020,15021,15022,15023,15024,15025,
8150715026,15027,15028,15029,15030,15031,15032,15033,15034,15035,15036,15037,
8150815038,15039,15040,15041,15042,15043,15044,15045,15046,15047,15048,15049,
8150915050,15051,15052,15053,15054,15055,15056,15057,15058,15059,15060,15061,
8151015062,15063,15064,15065,15066,15067,15068,15069,15070,15071,15072,15073,
8151115074,15075,15076,15077,15078,15079,15080,15081,15082,15083,15084,15085,
8151215086,15087,15088,15089,15090,15091,15092,15093,15094,15095,15096,15097,
8151315098,15099,15100,15101,15102,15103,15104,15105,15106,15107,15108,15109,
8151415110,15111,15112,15113,15114,15115,15116,15117,15118,15119,15120,15121,
8151515122,15123,15124,15125,15126,15127,15128,15129,15130,15131,15132,15133,
8151615134,15135,15136,15137,15138,15139,15140,15141,15142,15143,15144,15145,
8151715146,15147,15148,15149,15150,15151,15152,15153,15154,15155,15156,15157,
8151815158,15159,15160,15161,15162,15163,15164,15165,15166,15167,15168,15169,
8151915170,15171,15172,15173,15174,15175,15176,15177,15178,15179,15180,15181,
8152015182,15183,15184,15185,15186,15187,15188,15189,15190,15191,15192,15193,
8152115194,15195,15196,15197,15198,15199,15200,15201,15202,15203,15204,15205,
8152215206,15207,15208,15209,15210,15211,15212,15213,15214,15215,15216,15217,
8152315218,15219,15220,15221,15222,15223,15224,15225,15226,15227,15228,15229,
8152415230,15231,15232,15233,15234,15235,15236,15237,15238,15239,15240,15241,
8152515242,15243,15244,15245,15246,15247,15248,15249,15250,15251,15252,15253,
8152615254,15255,15256,15257,15258,15259,15260,15261,15262,15263,15264,15265,
8152715266,15267,15268,15269,15270,15271,15272,15273,15274,15275,15276,15277,
8152815278,15279,15280,15281,15282,15283,15284,15285,15286,15287,15288,15289,
8152915290,15291,15292,15293,15294,15295,15296,15297,15298,15299,15300,15301,
8153015302,15303,15304,15305,15306,15307,15308,15309,15310,15311,15312,15313,
8153115314,15315,15316,15317,15318,15319,15320,15321,15322,15323,15324,15325,
8153215326,15327,15328,15329,15330,15331,15332,15333,15334,15335,15336,15337,
8153315338,15339,15340,15341,15342,15343,15344,15345,15346,15347,15348,15349,
8153415350,15351,15352,15353,15354,15355,15356,15357,15358,15359,15360,15361,
8153515362,15363,15364,15365,15366,15367,15368,15369,15370,15371,15372,15373,
8153615374,15375,15376,15377,15378,15379,15380,15381,15382,15383,15384,15385,
8153715386,15387,15388,15389,15390,15391,15392,15393,15394,15395,15396,15397,
8153815398,15399,15400,15401,15402,15403,15404,15405,15406,15407,15408,15409,
8153915410,15411,15412,15413,15414,15415,15416,15417,15418,15419,15420,15421,
8154015422,15423,15424,15425,15426,15427,15428,15429,15430,15431,15432,15433,
8154115434,15435,15436,15437,15438,15439,15440,15441,15442,15443,15444,15445,
8154215446,15447,15448,15449,15450,15451,15452,15453,15454,15455,15456,15457,
8154315458,15459,15460,15461,15462,15463,15464,15465,15466,15467,15468,15469,
8154415470,15471,15472,15473,15474,15475,15476,15477,15478,15479,15480,15481,
8154515482,15483,15484,15485,15486,15487,15488,15489,15490,15491,15492,15493,
8154615494,15495,15496,15497,15498,15499,15500,15501,15502,15503,15504,15505,
8154715506,15507,15508,15509,15510,15511,15512,15513,15514,15515,15516,15517,
8154815518,15519,15520,15521,15522,15523,15524,15525,15526,15527,15528,15529,
8154915530,15531,15532,15533,15534,15535,15536,15537,15538,15539,15540,15541,
8155015542,15543,15544,15545,15546,15547,15548,15549,15550,15551,15552,15553,
8155115554,15555,15556,15557,15558,15559,15560,15561,15562,15563,15564,15565,
8155215566,15567,15568,15569,15570,15571,15572,15573,15574,15575,15576,15577,
8155315578,15579,15580,15581,15582,15583,15584,15585,15586,15587,15588,15589,
8155415590,15591,15592,15593,15594,15595,15596,15597,15598,15599,15600,15601,
8155515602,15603,15604,15605,15606,15607,15608,15609,15610,15611,15612,15613,
8155615614,15615,15616,15617,15618,15619,15620,15621,15622,15623,15624,15625,
8155715626,15627,15628,15629,15630,15631,15632,15633,15634,15635,15636,15637,
8155815638,15639,15640,15641,15642,15643,15644,15645,15646,15647,15648,15649,
8155915650,15651,15652,15653,15654,15655,15656,15657,15658,15659,15660,15661,
8156015662,15663,15664,15665,15666,15667,15668,15669,15670,15671,15672,15673,
8156115674,15675,15676,15677,15678,15679,15680,15681,15682,15683,15684,15685,
8156215686,15687,15688,15689,15690,15691,15692,15693,15694,15695,15696,15697,
8156315698,15699,15700,15701,15702,15703,15704,15705,15706,15707,15708,15709,
8156415710,15711,15712,15713,15714,15715,15716,15717,15718,15719,15720,15721,
8156515722,15723,15724,15725,15726,15727,15728,15729,15730,15731,15732,15733,
8156615734,15735,15736,15737,15738,15739,15740,15741,15742,15743,15744,15745,
8156715746,15747,15748,15749,15750,15751,15752,15753,15754,15755,15756,15757,
8156815758,15759,15760,15761,15762,15763,15764,15765,15766,15767,15768,15769,
8156915770,15771,15772,15773,15774,15775,15776,15777,15778,15779,15780,15781,
8157015782,15783,15784,15785,15786,15787,15788,15789,15790,15791,15792,15793,
8157115794,15795,15796,15797,15798,15799,15800,15801,15802,15803,15804,15805,
8157215806,15807,15808,15809,15810,15811,15812,15813,15814,15815,15816,15817,
8157315818,15819,15820,15821,15822,15823,15824,15825,15826,15827,15828,15829,
8157415830,15831,15832,15833,15834,15835,15836,15837,15838,15839,15840,15841,
8157515842,15843,15844,15845,15846,15847,15848,15849,15850,15851,15852,15853,
8157615854,15855,15856,15857,15858,15859,15860,15861,15862,15863,15864,15865,
8157715866,15867,15868,15869,15870,15871,15872,15873,15874,15875,15876,15877,
8157815878,15879,15880,15881,15882,15883,15884,15885,15886,15887,15888,15889,
8157915890,15891,15892,15893,15894,15895,15896,15897,15898,15899,15900,15901,
8158015902,15903,15904,15905,15906,15907,15908,15909,15910,15911,15912,15913,
8158115914,15915,15916,15917,15918,15919,15920,15921,15922,15923,15924,15925,
8158215926,15927,15928,15929,15930,15931,15932,15933,15934,15935,15936,15937,
8158315938,15939,15940,15941,15942,15943,15944,15945,15946,15947,15948,15949,
8158415950,15951,15952,15953,15954,15955,15956,15957,15958,15959,15960,15961,
8158515962,15963,15964,15965,15966,15967,15968,15969,15970,15971,15972,15973,
8158615974,15975,15976,15977,15978,15979,15980,15981,15982,15983,15984,15985,
8158715986,15987,15988,15989,15990,15991,15992,15993,15994,15995,15996,15997,
8158815998,15999,16000,16001,16002,16003,16004,16005,16006,16007,16008,16009,
8158916010,16011,16012,16013,16014,16015,16016,16017,16018,16019,16020,16021,
8159016022,16023,16024,16025,16026,16027,16028,16029,16030,16031,16032,16033,
8159116034,16035,16036,16037,16038,16039,16040,16041,16042,16043,16044,16045,
8159216046,16047,16048,16049,16050,16051,16052,16053,16054,16055,16056,16057,
8159316058,16059,16060,16061,16062,16063,16064,16065,16066,16067,16068,16069,
8159416070,16071,16072,16073,16074,16075,16076,16077,16078,16079,16080,16081,
8159516082,16083,16084,16085,16086,16087,16088,16089,16090,16091,16092,16093,
8159616094,16095,16096,16097,16098,16099,16100,16101,16102,16103,16104,16105,
8159716106,16107,16108,16109,16110,16111,16112,16113,16114,16115,16116,16117,
8159816118,16119,16120,16121,16122,16123,16124,16125,16126,16127,16128,16129,
8159916130,16131,16132,16133,16134,16135,16136,16137,16138,16139,16140,16141,
8160016142,16143,16144,16145,16146,16147,16148,16149,16150,16151,16152,16153,
8160116154,16155,16156,16157,16158,16159,16160,16161,16162,16163,16164,16165,
8160216166,16167,16168,16169,16170,16171,16172,16173,16174,16175,16176,16177,
8160316178,16179,16180,16181,16182,16183,16184,16185,16186,16187,16188,16189,
8160416190,16191,16192,16193,16194,16195,16196,16197,16198,16199,16200,16201,
8160516202,16203,16204,16205,16206,16207,16208,16209,16210,16211,16212,16213,
8160616214,16215,16216,16217,16218,16219,16220,16221,16222,16223,16224,16225,
8160716226,16227,16228,16229,16230,16231,16232,16233,16234,16235,16236,16237,
8160816238,16239,16240,16241,16242,16243,16244,16245,16246,16247,16248,16249,
8160916250,16251,16252,16253,16254,16255,16256,16257,16258,16259,16260,16261,
8161016262,16263,16264,16265,16266,16267,16268,16269,16270,16271,16272,16273,
8161116274,16275,16276,16277,16278,16279,16280,16281,16282,16283,16284,16285,
8161216286,16287,16288,16289,16290,16291,16292,16293,16294,16295,16296,16297,
8161316298,16299,16300,16301,16302,16303,16304,16305,16306,16307,16308,16309,
8161416310,16311,16312,16313,16314,16315,16316,16317,16318,16319,16320,16321,
8161516322,16323,16324,16325,16326,16327,16328,16329,16330,16331,16332,16333,
8161616334,16335,16336,16337,16338,16339,16340,16341,16342,16343,16344,16345,
8161716346,16347,16348,16349,16350,16351,16352,16353,16354,16355,16356,16357,
8161816358,16359,16360,16361,16362,16363,16364,16365,16366,16367,16368,16369,
8161916370,16371,16372,16373,16374,16375,16376,16377,16378,16379,16380,16381,
8162016382,16383,16384,16385,16386,16387,16388,16389,16390,16391,16392,16393,
8162116394,16395,16396,16397,16398,16399,16400,16401,16402,16403,16404,16405,
8162216406,16407,16408,16409,16410,16411,16412,16413,16414,16415,16416,16417,
8162316418,16419,16420,16421,16422,16423,16424,16425,16426,16427,16428,16429,
8162416430,16431,16432,16433,16434,16435,16436,16437,16438,16439,16440,16441,
8162516442,16443,16444,16445,16446,16447,16448,16449,16450,16451,16452,16453,
8162616454,16455,16456,16457,16458,16459,16460,16461,16462,16463,16464,16465,
8162716466,16467,16468,16469,16470,16471,16472,16473,16474,16475,16476,16477,
8162816478,16479,16480,16481,16482,16483,16484,16485,16486,16487,16488,16489,
8162916490,16491,16492,16493,16494,16495,16496,16497,16498,16499,16500,16501,
8163016502,16503,16504,16505,16506,16507,16508,16509,16510,16511,16512,16513,
8163116514,16515,16516,16517,16518,16519,16520,16521,16522,16523,16524,16525,
8163216526,16527,16528,16529,16530,16531,16532,16533,16534,16535,16536,16537,
8163316538,16539,16540,16541,16542,16543,16544,16545,16546,16547,16548,16549,
8163416550,16551,16552,16553,16554,16555,16556,16557,16558,16559,16560,16561,
8163516562,16563,16564,16565,16566,16567,16568,16569,16570,16571,16572,16573,
8163616574,16575,16576,16577,16578,16579,16580,16581,16582,16583,16584,16585,
8163716586,16587,16588,16589,16590,16591,16592,16593,16594,16595,16596,16597,
8163816598,16599,16600,16601,16602,16603,16604,16605,16606,16607,16608,16609,
8163916610,16611,16612,16613,16614,16615,16616,16617,16618,16619,16620,16621,
8164016622,16623,16624,16625,16626,16627,16628,16629,16630,16631,16632,16633,
8164116634,16635,16636,16637,16638,16639,16640,16641,16642,16643,16644,16645,
8164216646,16647,16648,16649,16650,16651,16652,16653,16654,16655,16656,16657,
8164316658,16659,16660,16661,16662,16663,16664,16665,16666,16667,16668,16669,
8164416670,16671,16672,16673,16674,16675,16676,16677,16678,16679,16680,16681,
8164516682,16683,16684,16685,16686,16687,16688,16689,16690,16691,16692,16693,
8164616694,16695,16696,16697,16698,16699,16700,16701,16702,16703,16704,16705,
8164716706,16707,16708,16709,16710,16711,16712,16713,16714,16715,16716,16717,
8164816718,16719,16720,16721,16722,16723,16724,16725,16726,16727,16728,16729,
8164916730,16731,16732,16733,16734,16735,16736,16737,16738,16739,16740,16741,
8165016742,16743,16744,16745,16746,16747,16748,16749,16750,16751,16752,16753,
8165116754,16755,16756,16757,16758,16759,16760,16761,16762,16763,16764,16765,
8165216766,16767,16768,16769,16770,16771,16772,16773,16774,16775,16776,16777,
8165316778,16779,16780,16781,16782,16783,16784,16785,16786,16787,16788,16789,
8165416790,16791,16792,16793,16794,16795,16796,16797,16798,16799,16800,16801,
8165516802,16803,16804,16805,16806,16807,16808,16809,16810,16811,16812,16813,
8165616814,16815,16816,16817,16818,16819,16820,16821,16822,16823,16824,16825,
8165716826,16827,16828,16829,16830,16831,16832,16833,16834,16835,16836,16837,
8165816838,16839,16840,16841,16842,16843,16844,16845,16846,16847,16848,16849,
8165916850,16851,16852,16853,16854,16855,16856,16857,16858,16859,16860,16861,
8166016862,16863,16864,16865,16866,16867,16868,16869,16870,16871,16872,16873,
8166116874,16875,16876,16877,16878,16879,16880,16881,16882,16883,16884,16885,
8166216886,16887,16888,16889,16890,16891,16892,16893,16894,16895,16896,16897,
8166316898,16899,16900,16901,16902,16903,16904,16905,16906,16907,16908,16909,
8166416910,16911,16912,16913,16914,16915,16916,16917,16918,16919,16920,16921,
8166516922,16923,16924,16925,16926,16927,16928,16929,16930,16931,16932,16933,
8166616934,16935,16936,16937,16938,16939,16940,16941,16942,16943,16944,16945,
8166716946,16947,16948,16949,16950,16951,16952,16953,16954,16955,16956,16957,
8166816958,16959,16960,16961,16962,16963,16964,16965,16966,16967,16968,16969,
8166916970,16971,16972,16973,16974,16975,16976,16977,16978,16979,16980,16981,
8167016982,16983,16984,16985,16986,16987,16988,16989,16990,16991,16992,16993,
8167116994,16995,16996,16997,16998,16999,17000,17001,17002,17003,17004,17005,
8167217006,17007,17008,17009,17010,17011,17012,17013,17014,17015,17016,17017,
8167317018,17019,17020,17021,17022,17023,17024,17025,17026,17027,17028,17029,
8167417030,17031,17032,17033,17034,17035,17036,17037,17038,17039,17040,17041,
8167517042,17043,17044,17045,17046,17047,17048,17049,17050,17051,17052,17053,
8167617054,17055,17056,17057,17058,17059,17060,17061,17062,17063,17064,17065,
8167717066,17067,17068,17069,17070,17071,17072,17073,17074,17075,17076,17077,
8167817078,17079,17080,17081,17082,17083,17084,17085,17086,17087,17088,17089,
8167917090,17091,17092,17093,17094,17095,17096,17097,17098,17099,17100,17101,
8168017102,17103,17104,17105,17106,17107,17108,17109,17110,17111,17112,17113,
8168117114,17115,17116,17117,17118,17119,17120,17121,17122,17123,17124,17125,
8168217126,17127,17128,17129,17130,17131,17132,17133,17134,17135,17136,17137,
8168317138,17139,17140,17141,17142,17143,17144,17145,17146,17147,17148,17149,
8168417150,17151,17152,17153,17154,17155,17156,17157,17158,17159,17160,17161,
8168517162,17163,17164,17165,17166,17167,17168,17169,17170,17171,17172,17173,
8168617174,17175,17176,17177,17178,17179,17180,17181,17182,17183,17184,17185,
8168717186,17187,17188,17189,17190,17191,17192,17193,17194,17195,17196,17197,
8168817198,17199,17200,17201,17202,17203,17204,17205,17206,17207,17208,17209,
8168917210,17211,17212,17213,17214,17215,17216,17217,17218,17219,17220,17221,
8169017222,17223,17224,17225,17226,17227,17228,17229,17230,17231,17232,17233,
8169117234,17235,17236,17237,17238,17239,17240,17241,17242,17243,17244,17245,
8169217246,17247,17248,17249,17250,17251,17252,17253,17254,17255,17256,17257,
8169317258,17259,17260,17261,17262,17263,17264,17265,17266,17267,17268,17269,
8169417270,17271,17272,17273,17274,17275,17276,17277,17278,17279,17280,17281,
8169517282,17283,17284,17285,17286,17287,17288,17289,17290,17291,17292,17293,
8169617294,17295,17296,17297,17298,17299,17300,17301,17302,17303,17304,17305,
8169717306,17307,17308,17309,17310,17311,17312,17313,17314,17315,17316,17317,
8169817318,17319,17320,17321,17322,17323,17324,17325,17326,17327,17328,17329,
8169917330,17331,17332,17333,17334,17335,17336,17337,17338,17339,17340,17341,
8170017342,17343,17344,17345,17346,17347,17348,17349,17350,17351,17352,17353,
8170117354,17355,17356,17357,17358,17359,17360,17361,17362,17363,17364,17365,
8170217366,17367,17368,17369,17370,17371,17372,17373,17374,17375,17376,17377,
8170317378,17379,17380,17381,17382,17383,17384,17385,17386,17387,17388,17389,
8170417390,17391,17392,17393,17394,17395,17396,17397,17398,17399,17400,17401,
8170517402,17403,17404,17405,17406,17407,17408,17409,17410,17411,17412,17413,
8170617414,17415,17416,17417,17418,17419,17420,17421,17422,17423,17424,17425,
8170717426,17427,17428,17429,17430,17431,17432,17433,17434,17435,17436,17437,
8170817438,17439,17440,17441,17442,17443,17444,17445,17446,17447,17448,17449,
8170917450,17451,17452,17453,17454,17455,17456,17457,17458,17459,17460,17461,
8171017462,17463,17464,17465,17466,17467,17468,17469,17470,17471,17472,17473,
8171117474,17475,17476,17477,17478,17479,17480,17481,17482,17483,17484,17485,
8171217486,17487,17488,17489,17490,17491,17492,17493,17494,17495,17496,17497,
8171317498,17499,17500,17501,17502,17503,17504,17505,17506,17507,17508,17509,
8171417510,17511,17512,17513,17514,17515,17516,17517,17518,17519,17520,17521,
8171517522,17523,17524,17525,17526,17527,17528,17529,17530,17531,17532,17533,
8171617534,17535,17536,17537,17538,17539,17540,17541,17542,17543,17544,17545,
8171717546,17547,17548,17549,17550,17551,17552,17553,17554,17555,17556,17557,
8171817558,17559,17560,17561,17562,17563,17564,17565,17566,17567,17568,17569,
8171917570,17571,17572,17573,17574,17575,17576,17577,17578,17579,17580,17581,
8172017582,17583,17584,17585,17586,17587,17588,17589,17590,17591,17592,17593,
8172117594,17595,17596,17597,17598,17599,17600,17601,17602,17603,17604,17605,
8172217606,17607,17608,17609,17610,17611,17612,17613,17614,17615,17616,17617,
8172317618,17619,17620,17621,17622,17623,17624,17625,17626,17627,17628,17629,
8172417630,17631,17632,17633,17634,17635,17636,17637,17638,17639,17640,17641,
8172517642,17643,17644,17645,17646,17647,17648,17649,17650,17651,17652,17653,
8172617654,17655,17656,17657,17658,17659,17660,17661,17662,17663,17664,17665,
8172717666,17667,17668,17669,17670,17671,17672,17673,17674,17675,17676,17677,
8172817678,17679,17680,17681,17682,17683,17684,17685,17686,17687,17688,17689,
8172917690,17691,17692,17693,17694,17695,17696,17697,17698,17699,17700,17701,
8173017702,17703,17704,17705,17706,17707,17708,17709,17710,17711,17712,17713,
8173117714,17715,17716,17717,17718,17719,17720,17721,17722,17723,17724,17725,
8173217726,17727,17728,17729,17730,17731,17732,17733,17734,17735,17736,17737,
8173317738,17739,17740,17741,17742,17743,17744,17745,17746,17747,17748,17749,
8173417750,17751,17752,17753,17754,17755,17756,17757,17758,17759,17760,17761,
8173517762,17763,17764,17765,17766,17767,17768,17769,17770,17771,17772,17773,
8173617774,17775,17776,17777,17778,17779,17780,17781,17782,17783,17784,17785,
8173717786,17787,17788,17789,17790,17791,17792,17793,17794,17795,17796,17797,
8173817798,17799,17800,17801,17802,17803,17804,17805,17806,17807,17808,17809,
8173917810,17811,17812,17813,17814,17815,17816,17817,17818,17819,17820,17821,
8174017822,17823,17824,17825,17826,17827,17828,17829,17830,17831,17832,17833,
8174117834,17835,17836,17837,17838,17839,17840,17841,17842,17843,17844,17845,
8174217846,17847,17848,17849,17850,17851,17852,17853,17854,17855,17856,17857,
8174317858,17859,17860,17861,17862,17863,17864,17865,17866,17867,17868,17869,
8174417870,17871,17872,17873,17874,17875,17876,17877,17878,17879,17880,17881,
8174517882,17883,17884,17885,17886,17887,17888,17889,17890,17891,17892,17893,
8174617894,17895,17896,17897,17898,17899,17900,17901,17902,17903,17904,17905,
8174717906,17907,17908,17909,17910,17911,17912,17913,17914,17915,17916,17917,
8174817918,17919,17920,17921,17922,17923,17924,17925,17926,17927,17928,17929,
8174917930,17931,17932,17933,17934,17935,17936,17937,17938,17939,17940,17941,
8175017942,17943,17944,17945,17946,17947,17948,17949,17950,17951,17952,17953,
8175117954,17955,17956,17957,17958,17959,17960,17961,17962,17963,17964,17965,
8175217966,17967,17968,17969,17970,17971,17972,17973,17974,17975,17976,17977,
8175317978,17979,17980,17981,17982,17983,17984,17985,17986,17987,17988,17989,
8175417990,17991,17992,17993,17994,17995,17996,17997,17998,17999,18000,18001,
8175518002,18003,18004,18005,18006,18007,18008,18009,18010,18011,18012,18013,
8175618014,18015,18016,18017,18018,18019,18020,18021,18022,18023,18024,18025,
8175718026,18027,18028,18029,18030,18031,18032,18033,18034,18035,18036,18037,
8175818038,18039,18040,18041,18042,18043,18044,18045,18046,18047,18048,18049,
8175918050,18051,18052,18053,18054,18055,18056,18057,18058,18059,18060,18061,
8176018062,18063,18064,18065,18066,18067,18068,18069,18070,18071,18072,18073,
8176118074,18075,18076,18077,18078,18079,18080,18081,18082,18083,18084,18085,
8176218086,18087,18088,18089,18090,18091,18092,18093,18094,18095,18096,18097,
8176318098,18099,18100,18101,18102,18103,18104,18105,18106,18107,18108,18109,
8176418110,18111,18112,18113,18114,18115,18116,18117,18118,18119,18120,18121,
8176518122,18123,18124,18125,18126,18127,18128,18129,18130,18131,18132,18133,
8176618134,18135,18136,18137,18138,18139,18140,18141,18142,18143,18144,18145,
8176718146,18147,18148,18149,18150,18151,18152,18153,18154,18155,18156,18157,
8176818158,18159,18160,18161,18162,18163,18164,18165,18166,18167,18168,18169,
8176918170,18171,18172,18173,18174,18175,18176,18177,18178,18179,18180,18181,
8177018182,18183,18184,18185,18186,18187,18188,18189,18190,18191,18192,18193,
8177118194,18195,18196,18197,18198,18199,18200,18201,18202,18203,18204,18205,
8177218206,18207,18208,18209,18210,18211,18212,18213,18214,18215,18216,18217,
8177318218,18219,18220,18221,18222,18223,18224,18225,18226,18227,18228,18229,
8177418230,18231,18232,18233,18234,18235,18236,18237,18238,18239,18240,18241,
8177518242,18243,18244,18245,18246,18247,18248,18249,18250,18251,18252,18253,
8177618254,18255,18256,18257,18258,18259,18260,18261,18262,18263,18264,18265,
8177718266,18267,18268,18269,18270,18271,18272,18273,18274,18275,18276,18277,
8177818278,18279,18280,18281,18282,18283,18284,18285,18286,18287,18288,18289,
8177918290,18291,18292,18293,18294,18295,18296,18297,18298,18299,18300,18301,
8178018302,18303,18304,18305,18306,18307,18308,18309,18310,18311,18312,18313,
8178118314,18315,18316,18317,18318,18319,18320,18321,18322,18323,18324,18325,
8178218326,18327,18328,18329,18330,18331,18332,18333,18334,18335,18336,18337,
8178318338,18339,18340,18341,18342,18343,18344,18345,18346,18347,18348,18349,
8178418350,18351,18352,18353,18354,18355,18356,18357,18358,18359,18360,18361,
8178518362,18363,18364,18365,18366,18367,18368,18369,18370,18371,18372,18373,
8178618374,18375,18376,18377,18378,18379,18380,18381,18382,18383,18384,18385,
8178718386,18387,18388,18389,18390,18391,18392,18393,18394,18395,18396,18397,
8178818398,18399,18400,18401,18402,18403,18404,18405,18406,18407,18408,18409,
8178918410,18411,18412,18413,18414,18415,18416,18417,18418,18419,18420,18421,
8179018422,18423,18424,18425,18426,18427,18428,18429,18430,18431,18432,18433,
8179118434,18435,18436,18437,18438,18439,18440,18441,18442,18443,18444,18445,
8179218446,18447,18448,18449,18450,18451,18452,18453,18454,18455,18456,18457,
8179318458,18459,18460,18461,18462,18463,18464,18465,18466,18467,18468,18469,
8179418470,18471,18472,18473,18474,18475,18476,18477,18478,18479,18480,18481,
8179518482,18483,18484,18485,18486,18487,18488,18489,18490,18491,18492,18493,
8179618494,18495,18496,18497,18498,18499,18500,18501,18502,18503,18504,18505,
8179718506,18507,18508,18509,18510,18511,18512,18513,18514,18515,18516,18517,
8179818518,18519,18520,18521,18522,18523,18524,18525,18526,18527,18528,18529,
8179918530,18531,18532,18533,18534,18535,18536,18537,18538,18539,18540,18541,
8180018542,18543,18544,18545,18546,18547,18548,18549,18550,18551,18552,18553,
8180118554,18555,18556,18557,18558,18559,18560,18561,18562,18563,18564,18565,
8180218566,18567,18568,18569,18570,18571,18572,18573,18574,18575,18576,18577,
8180318578,18579,18580,18581,18582,18583,18584,18585,18586,18587,18588,18589,
8180418590,18591,18592,18593,18594,18595,18596,18597,18598,18599,18600,18601,
8180518602,18603,18604,18605,18606,18607,18608,18609,18610,18611,18612,18613,
8180618614,18615,18616,18617,18618,18619,18620,18621,18622,18623,18624,18625,
8180718626,18627,18628,18629,18630,18631,18632,18633,18634,18635,18636,18637,
8180818638,18639,18640,18641,18642,18643,18644,18645,18646,18647,18648,18649,
8180918650,18651,18652,18653,18654,18655,18656,18657,18658,18659,18660,18661,
8181018662,18663,18664,18665,18666,18667,18668,18669,18670,18671,18672,18673,
8181118674,18675,18676,18677,18678,18679,18680,18681,18682,18683,18684,18685,
8181218686,18687,18688,18689,18690,18691,18692,18693,18694,18695,18696,18697,
8181318698,18699,18700,18701,18702,18703,18704,18705,18706,18707,18708,18709,
8181418710,18711,18712,18713,18714,18715,18716,18717,18718,18719,18720,18721,
8181518722,18723,18724,18725,18726,18727,18728,18729,18730,18731,18732,18733,
8181618734,18735,18736,18737,18738,18739,18740,18741,18742,18743,18744,18745,
8181718746,18747,18748,18749,18750,18751,18752,18753,18754,18755,18756,18757,
8181818758,18759,18760,18761,18762,18763,18764,18765,18766,18767,18768,18769,
8181918770,18771,18772,18773,18774,18775,18776,18777,18778,18779,18780,18781,
8182018782,18783,18784,18785,18786,18787,18788,18789,18790,18791,18792,18793,
8182118794,18795,18796,18797,18798,18799,18800,18801,18802,18803,18804,18805,
8182218806,18807,18808,18809,18810,18811,18812,18813,18814,18815,18816,18817,
8182318818,18819,18820,18821,18822,18823,18824,18825,18826,18827,18828,18829,
8182418830,18831,18832,18833,18834,18835,18836,18837,18838,18839,18840,18841,
8182518842,18843,18844,18845,18846,18847,18848,18849,18850,18851,18852,18853,
8182618854,18855,18856,18857,18858,18859,18860,18861,18862,18863,18864,18865,
8182718866,18867,18868,18869,18870,18871,18872,18873,18874,18875,18876,18877,
8182818878,18879,18880,18881,18882,18883,18884,18885,18886,18887,18888,18889,
8182918890,18891,18892,18893,18894,18895,18896,18897,18898,18899,18900,18901,
8183018902,18903,18904,18905,18906,18907,18908,18909,18910,18911,18912,18913,
8183118914,18915,18916,18917,18918,18919,18920,18921,18922,18923,18924,18925,
8183218926,18927,18928,18929,18930,18931,18932,18933,18934,18935,18936,18937,
8183318938,18939,18940,18941,18942,18943,18944,18945,18946,18947,18948,18949,
8183418950,18951,18952,18953,18954,18955,18956,18957,18958,18959,18960,18961,
8183518962,18963,18964,18965,18966,18967,18968,18969,18970,18971,18972,18973,
8183618974,18975,18976,18977,18978,18979,18980,18981,18982,18983,18984,18985,
8183718986,18987,18988,18989,18990,18991,18992,18993,18994,18995,18996,18997,
8183818998,18999,19000,19001,19002,19003,19004,19005,19006,19007,19008,19009,
8183919010,19011,19012,19013,19014,19015,19016,19017,19018,19019,19020,19021,
8184019022,19023,19024,19025,19026,19027,19028,19029,19030,19031,19032,19033,
8184119034,19035,19036,19037,19038,19039,19040,19041,19042,19043,19044,19045,
8184219046,19047,19048,19049,19050,19051,19052,19053,19054,19055,19056,19057,
8184319058,19059,19060,19061,19062,19063,19064,19065,19066,19067,19068,19069,
8184419070,19071,19072,19073,19074,19075,19076,19077,19078,19079,19080,19081,
8184519082,19083,19084,19085,19086,19087,19088,19089,19090,19091,19092,19093,
8184619094,19095,19096,19097,19098,19099,19100,19101,19102,19103,19104,19105,
8184719106,19107,19108,19109,19110,19111,19112,19113,19114,19115,19116,19117,
8184819118,19119,19120,19121,19122,19123,19124,19125,19126,19127,19128,19129,
8184919130,19131,19132,19133,19134,19135,19136,19137,19138,19139,19140,19141,
8185019142,19143,19144,19145,19146,19147,19148,19149,19150,19151,19152,19153,
8185119154,19155,19156,19157,19158,19159,19160,19161,19162,19163,19164,19165,
8185219166,19167,19168,19169,19170,19171,19172,19173,19174,19175,19176,19177,
8185319178,19179,19180,19181,19182,19183,19184,19185,19186,19187,19188,19189,
8185419190,19191,19192,19193,19194,19195,19196,19197,19198,19199,19200,19201,
8185519202,19203,19204,19205,19206,19207,19208,19209,19210,19211,19212,19213,
8185619214,19215,19216,19217,19218,19219,19220,19221,19222,19223,19224,19225,
8185719226,19227,19228,19229,19230,19231,19232,19233,19234,19235,19236,19237,
8185819238,19239,19240,19241,19242,19243,19244,19245,19246,19247,19248,19249,
8185919250,19251,19252,19253,19254,19255,19256,19257,19258,19259,19260,19261,
8186019262,19263,19264,19265,19266,19267,19268,19269,19270,19271,19272,19273,
8186119274,19275,19276,19277,19278,19279,19280,19281,19282,19283,19284,19285,
8186219286,19287,19288,19289,19290,19291,19292,19293,19294,19295,19296,19297,
8186319298,19299,19300,19301,19302,19303,19304,19305,19306,19307,19308,19309,
8186419310,19311,19312,19313,19314,19315,19316,19317,19318,19319,19320,19321,
8186519322,19323,19324,19325,19326,19327,19328,19329,19330,19331,19332,19333,
8186619334,19335,19336,19337,19338,19339,19340,19341,19342,19343,19344,19345,
8186719346,19347,19348,19349,19350,19351,19352,19353,19354,19355,19356,19357,
8186819358,19359,19360,19361,19362,19363,19364,19365,19366,19367,19368,19369,
8186919370,19371,19372,19373,19374,19375,19376,19377,19378,19379,19380,19381,
8187019382,19383,19384,19385,19386,19387,19388,19389,19390,19391,19392,19393,
8187119394,19395,19396,19397,19398,19399,19400,19401,19402,19403,19404,19405,
8187219406,19407,19408,19409,19410,19411,19412,19413,19414,19415,19416,19417,
8187319418,19419,19420,19421,19422,19423,19424,19425,19426,19427,19428,19429,
8187419430,19431,19432,19433,19434,19435,19436,19437,19438,19439,19440,19441,
8187519442,19443,19444,19445,19446,19447,19448,19449,19450,19451,19452,19453,
8187619454,19455,19456,19457,19458,19459,19460,19461,19462,19463,19464,19465,
8187719466,19467,19468,19469,19470,19471,19472,19473,19474,19475,19476,19477,
8187819478,19479,19480,19481,19482,19483,19484,19485,19486,19487,19488,19489,
8187919490,19491,19492,19493,19494,19495,19496,19497,19498,19499,19500,19501,
8188019502,19503,19504,19505,19506,19507,19508,19509,19510,19511,19512,19513,
8188119514,19515,19516,19517,19518,19519,19520,19521,19522,19523,19524,19525,
8188219526,19527,19528,19529,19530,19531,19532,19533,19534,19535,19536,19537,
8188319538,19539,19540,19541,19542,19543,19544,19545,19546,19547,19548,19549,
8188419550,19551,19552,19553,19554,19555,19556,19557,19558,19559,19560,19561,
8188519562,19563,19564,19565,19566,19567,19568,19569,19570,19571,19572,19573,
8188619574,19575,19576,19577,19578,19579,19580,19581,19582,19583,19584,19585,
8188719586,19587,19588,19589,19590,19591,19592,19593,19594,19595,19596,19597,
8188819598,19599,19600,19601,19602,19603,19604,19605,19606,19607,19608,19609,
8188919610,19611,19612,19613,19614,19615,19616,19617,19618,19619,19620,19621,
8189019622,19623,19624,19625,19626,19627,19628,19629,19630,19631,19632,19633,
8189119634,19635,19636,19637,19638,19639,19640,19641,19642,19643,19644,19645,
8189219646,19647,19648,19649,19650,19651,19652,19653,19654,19655,19656,19657,
8189319658,19659,19660,19661,19662,19663,19664,19665,19666,19667,19668,19669,
8189419670,19671,19672,19673,19674,19675,19676,19677,19678,19679,19680,19681,
8189519682,19683,19684,19685,19686,19687,19688,19689,19690,19691,19692,19693,
8189619694,19695,19696,19697,19698,19699,19700,19701,19702,19703,19704,19705,
8189719706,19707,19708,19709,19710,19711,19712,19713,19714,19715,19716,19717,
8189819718,19719,19720,19721,19722,19723,19724,19725,19726,19727,19728,19729,
8189919730,19731,19732,19733,19734,19735,19736,19737,19738,19739,19740,19741,
8190019742,19743,19744,19745,19746,19747,19748,19749,19750,19751,19752,19753,
8190119754,19755,19756,19757,19758,19759,19760,19761,19762,19763,19764,19765,
8190219766,19767,19768,19769,19770,19771,19772,19773,19774,19775,19776,19777,
8190319778,19779,19780,19781,19782,19783,19784,19785,19786,19787,19788,19789,
8190419790,19791,19792,19793,19794,19795,19796,19797,19798,19799,19800,19801,
8190519802,19803,19804,19805,19806,19807,19808,19809,19810,19811,19812,19813,
8190619814,19815,19816,19817,19818,19819,19820,19821,19822,19823,19824,19825,
8190719826,19827,19828,19829,19830,19831,19832,19833,19834,19835,19836,19837,
8190819838,19839,19840,19841,19842,19843,19844,19845,19846,19847,19848,19849,
8190919850,19851,19852,19853,19854,19855,19856,19857,19858,19859,19860,19861,
8191019862,19863,19864,19865,19866,19867,19868,19869,19870,19871,19872,19873,
8191119874,19875,19876,19877,19878,19879,19880,19881,19882,19883,19884,19885,
8191219886,19887,19888,19889,19890,19891,19892,19893,19894,19895,19896,19897,
8191319898,19899,19900,19901,19902,19903,19904,19905,19906,19907,19908,19909,
8191419910,19911,19912,19913,19914,19915,19916,19917,19918,19919,19920,19921,
8191519922,19923,19924,19925,19926,19927,19928,19929,19930,19931,19932,19933,
8191619934,19935,19936,19937,19938,19939,19940,19941,19942,19943,19944,19945,
8191719946,19947,19948,19949,19950,19951,19952,19953,19954,19955,19956,19957,
8191819958,19959,19960,19961,19962,19963,19964,19965,19966,19967,19968,19969,
8191919970,19971,19972,19973,19974,19975,19976,19977,19978,19979,19980,19981,
8192019982,19983,19984,19985,19986,19987,19988,19989,19990,19991,19992,19993,
8192119994,19995,19996,19997,19998,19999,20000,20001,20002,20003,20004,20005,
8192220006,20007,20008,20009,20010,20011,20012,20013,20014,20015,20016,20017,
8192320018,20019,20020,20021,20022,20023,20024,20025,20026,20027,20028,20029,
8192420030,20031,20032,20033,20034,20035,20036,20037,20038,20039,20040,20041,
8192520042,20043,20044,20045,20046,20047,20048,20049,20050,20051,20052,20053,
8192620054,20055,20056,20057,20058,20059,20060,20061,20062,20063,20064,20065,
8192720066,20067,20068,20069,20070,20071,20072,20073,20074,20075,20076,20077,
8192820078,20079,20080,20081,20082,20083,20084,20085,20086,20087,20088,20089,
8192920090,20091,20092,20093,20094,20095,20096,20097,20098,20099,20100,20101,
8193020102,20103,20104,20105,20106,20107,20108,20109,20110,20111,20112,20113,
8193120114,20115,20116,20117,20118,20119,20120,20121,20122,20123,20124,20125,
8193220126,20127,20128,20129,20130,20131,20132,20133,20134,20135,20136,20137,
8193320138,20139,20140,20141,20142,20143,20144,20145,20146,20147,20148,20149,
8193420150,20151,20152,20153,20154,20155,20156,20157,20158,20159,20160,20161,
8193520162,20163,20164,20165,20166,20167,20168,20169,20170,20171,20172,20173,
8193620174,20175,20176,20177,20178,20179,20180,20181,20182,20183,20184,20185,
8193720186,20187,20188,20189,20190,20191,20192,20193,20194,20195,20196,20197,
8193820198,20199,20200,20201,20202,20203,20204,20205,20206,20207,20208,20209,
8193920210,20211,20212,20213,20214,20215,20216,20217,20218,20219,20220,20221,
8194020222,20223,20224,20225,20226,20227,20228,20229,20230,20231,20232,20233,
8194120234,20235,20236,20237,20238,20239,20240,20241,20242,20243,20244,20245,
8194220246,20247,20248,20249,20250,20251,20252,20253,20254,20255,20256,20257,
8194320258,20259,20260,20261,20262,20263,20264,20265,20266,20267,20268,20269,
8194420270,20271,20272,20273,20274,20275,20276,20277,20278,20279,20280,20281,
8194520282,20283,20284,20285,20286,20287,20288,20289,20290,20291,20292,20293,
8194620294,20295,20296,20297,20298,20299,20300,20301,20302,20303,20304,20305,
8194720306,20307,20308,20309,20310,20311,20312,20313,20314,20315,20316,20317,
8194820318,20319,20320,20321,20322,20323,20324,20325,20326,20327,20328,20329,
8194920330,20331,20332,20333,20334,20335,20336,20337,20338,20339,20340,20341,
8195020342,20343,20344,20345,20346,20347,20348,20349,20350,20351,20352,20353,
8195120354,20355,20356,20357,20358,20359,20360,20361,20362,20363,20364,20365,
8195220366,20367,20368,20369,20370,20371,20372,20373,20374,20375,20376,20377,
8195320378,20379,20380,20381,20382,20383,20384,20385,20386,20387,20388,20389,
8195420390,20391,20392,20393,20394,20395,20396,20397,20398,20399,20400,20401,
8195520402,20403,20404,20405,20406,20407,20408,20409,20410,20411,20412,20413,
8195620414,20415,20416,20417,20418,20419,20420,20421,20422,20423,20424,20425,
8195720426,20427,20428,20429,20430,20431,20432,20433,20434,20435,20436,20437,
8195820438,20439,20440,20441,20442,20443,20444,20445,20446,20447,20448,20449,
8195920450,20451,20452,20453,20454,20455,20456,20457,20458,20459,20460,20461,
8196020462,20463,20464,20465,20466,20467,20468,20469,20470,20471,20472,20473,
8196120474,20475,20476,20477,20478,20479,20480,20481,20482,20483,20484,20485,
8196220486,20487,20488,20489,20490,20491,20492,20493,20494,20495,20496,20497,
8196320498,20499,20500,20501,20502,20503,20504,20505,20506,20507,20508,20509,
8196420510,20511,20512,20513,20514,20515,20516,20517,20518,20519,20520,20521,
8196520522,20523,20524,20525,20526,20527,20528,20529,20530,20531,20532,20533,
8196620534,20535,20536,20537,20538,20539,20540,20541,20542,20543,20544,20545,
8196720546,20547,20548,20549,20550,20551,20552,20553,20554,20555,20556,20557,
8196820558,20559,20560,20561,20562,20563,20564,20565,20566,20567,20568,20569,
8196920570,20571,20572,20573,20574,20575,20576,20577,20578,20579,20580,20581,
8197020582,20583,20584,20585,20586,20587,20588,20589,20590,20591,20592,20593,
8197120594,20595,20596,20597,20598,20599,20600,20601,20602,20603,20604,20605,
8197220606,20607,20608,20609,20610,20611,20612,20613,20614,20615,20616,20617,
8197320618,20619,20620,20621,20622,20623,20624,20625,20626,20627,20628,20629,
8197420630,20631,20632,20633,20634,20635,20636,20637,20638,20639,20640,20641,
8197520642,20643,20644,20645,20646,20647,20648,20649,20650,20651,20652,20653,
8197620654,20655,20656,20657,20658,20659,20660,20661,20662,20663,20664,20665,
8197720666,20667,20668,20669,20670,20671,20672,20673,20674,20675,20676,20677,
8197820678,20679,20680,20681,20682,20683,20684,20685,20686,20687,20688,20689,
8197920690,20691,20692,20693,20694,20695,20696,20697,20698,20699,20700,20701,
8198020702,20703,20704,20705,20706,20707,20708,20709,20710,20711,20712,20713,
8198120714,20715,20716,20717,20718,20719,20720,20721,20722,20723,20724,20725,
8198220726,20727,20728,20729,20730,20731,20732,20733,20734,20735,20736,20737,
8198320738,20739,20740,20741,20742,20743,20744,20745,20746,20747,20748,20749,
8198420750,20751,20752,20753,20754,20755,20756,20757,20758,20759,20760,20761,
8198520762,20763,20764,20765,20766,20767,20768,20769,20770,20771,20772,20773,
8198620774,20775,20776,20777,20778,20779,20780,20781,20782,20783,20784,20785,
8198720786,20787,20788,20789,20790,20791,20792,20793,20794,20795,20796,20797,
8198820798,20799,20800,20801,20802,20803,20804,20805,20806,20807,20808,20809,
8198920810,20811,20812,20813,20814,20815,20816,20817,20818,20819,20820,20821,
8199020822,20823,20824,20825,20826,20827,20828,20829,20830,20831,20832,20833,
8199120834,20835,20836,20837,20838,20839,20840,20841,20842,20843,20844,20845,
8199220846,20847,20848,20849,20850,20851,20852,20853,20854,20855,20856,20857,
8199320858,20859,20860,20861,20862,20863,20864,20865,20866,20867,20868,20869,
8199420870,20871,20872,20873,20874,20875,20876,20877,20878,20879,20880,20881,
8199520882,20883,20884,20885,20886,20887,20888,20889,20890,20891,20892,20893,
8199620894,20895,20896,20897,20898,20899,20900,20901,20902,20903,20904,20905,
8199720906,20907,20908,20909,20910,20911,20912,20913,20914,20915,20916,20917,
8199820918,20919,20920,20921,20922,20923,20924,20925,20926,20927,20928,20929,
8199920930,20931,20932,20933,20934,20935,20936,20937,20938,20939,20940,20941,
8200020942,20943,20944,20945,20946,20947,20948,20949,20950,20951,20952,20953,
8200120954,20955,20956,20957,20958,20959,20960,20961,20962,20963,20964,20965,
8200220966,20967,20968,20969,20970,20971,20972,20973,20974,20975,20976,20977,
8200320978,20979,20980,20981,20982,20983,20984,20985,20986,20987,20988,20989,
8200420990,20991,20992,20993,20994,20995,20996,20997,20998,20999,21000,21001,
8200521002,21003,21004,21005,21006,21007,21008,21009,21010,21011,21012,21013,
8200621014,21015,21016,21017,21018,21019,21020,21021,21022,21023,21024,21025,
8200721026,21027,21028,21029,21030,21031,21032,21033,21034,21035,21036,21037,
8200821038,21039,21040,21041,21042,21043,21044,21045,21046,21047,21048,21049,
8200921050,21051,21052,21053,21054,21055,21056,21057,21058,21059,21060,21061,
8201021062,21063,21064,21065,21066,21067,21068,21069,21070,21071,21072,21073,
8201121074,21075,21076,21077,21078,21079,21080,21081,21082,21083,21084,21085,
8201221086,21087,21088,21089,21090,21091,21092,21093,21094,21095,21096,21097,
8201321098,21099,21100,21101,21102,21103,21104,21105,21106,21107,21108,21109,
8201421110,21111,21112,21113,21114,21115,21116,21117,21118,21119,21120,21121,
8201521122,21123,21124,21125,21126,21127,21128,21129,21130,21131,21132,21133,
8201621134,21135,21136,21137,21138,21139,21140,21141,21142,21143,21144,21145,
8201721146,21147,21148,21149,21150,21151,21152,21153,21154,21155,21156,21157,
8201821158,21159,21160,21161,21162,21163,21164,21165,21166,21167,21168,21169,
8201921170,21171,21172,21173,21174,21175,21176,21177,21178,21179,21180,21181,
8202021182,21183,21184,21185,21186,21187,21188,21189,21190,21191,21192,21193,
8202121194,21195,21196,21197,21198,21199,21200,21201,21202,21203,21204,21205,
8202221206,21207,21208,21209,21210,21211,21212,21213,21214,21215,21216,21217,
8202321218,21219,21220,21221,21222,21223,21224,21225,21226,21227,21228,21229,
8202421230,21231,21232,21233,21234,21235,21236,21237,21238,21239,21240,21241,
8202521242,21243,21244,21245,21246,21247,21248,21249,21250,21251,21252,21253,
8202621254,21255,21256,21257,21258,21259,21260,21261,21262,21263,21264,21265,
8202721266,21267,21268,21269,21270,21271,21272,21273,21274,21275,21276,21277,
8202821278,21279,21280,21281,21282,21283,21284,21285,21286,21287,21288,21289,
8202921290,21291,21292,21293,21294,21295,21296,21297,21298,21299,21300,21301,
8203021302,21303,21304,21305,21306,21307,21308,21309,21310,21311,21312,21313,
8203121314,21315,21316,21317,21318,21319,21320,21321,21322,21323,21324,21325,
8203221326,21327,21328,21329,21330,21331,21332,21333,21334,21335,21336,21337,
8203321338,21339,21340,21341,21342,21343,21344,21345,21346,21347,21348,21349,
8203421350,21351,21352,21353,21354,21355,21356,21357,21358,21359,21360,21361,
8203521362,21363,21364,21365,21366,21367,21368,21369,21370,21371,21372,21373,
8203621374,21375,21376,21377,21378,21379,21380,21381,21382,21383,21384,21385,
8203721386,21387,21388,21389,21390,21391,21392,21393,21394,21395,21396,21397,
8203821398,21399,21400,21401,21402,21403,21404,21405,21406,21407,21408,21409,
8203921410,21411,21412,21413,21414,21415,21416,21417,21418,21419,21420,21421,
8204021422,21423,21424,21425,21426,21427,21428,21429,21430,21431,21432,21433,
8204121434,21435,21436,21437,21438,21439,21440,21441,21442,21443,21444,21445,
8204221446,21447,21448,21449,21450,21451,21452,21453,21454,21455,21456,21457,
8204321458,21459,21460,21461,21462,21463,21464,21465,21466,21467,21468,21469,
8204421470,21471,21472,21473,21474,21475,21476,21477,21478,21479,21480,21481,
8204521482,21483,21484,21485,21486,21487,21488,21489,21490,21491,21492,21493,
8204621494,21495,21496,21497,21498,21499,21500,21501,21502,21503,21504,21505,
8204721506,21507,21508,21509,21510,21511,21512,21513,21514,21515,21516,21517,
8204821518,21519,21520,21521,21522,21523,21524,21525,21526,21527,21528,21529,
8204921530,21531,21532,21533,21534,21535,21536,21537,21538,21539,21540,21541,
8205021542,21543,21544,21545,21546,21547,21548,21549,21550,21551,21552,21553,
8205121554,21555,21556,21557,21558,21559,21560,21561,21562,21563,21564,21565,
8205221566,21567,21568,21569,21570,21571,21572,21573,21574,21575,21576,21577,
8205321578,21579,21580,21581,21582,21583,21584,21585,21586,21587,21588,21589,
8205421590,21591,21592,21593,21594,21595,21596,21597,21598,21599,21600,21601,
8205521602,21603,21604,21605,21606,21607,21608,21609,21610,21611,21612,21613,
8205621614,21615,21616,21617,21618,21619,21620,21621,21622,21623,21624,21625,
8205721626,21627,21628,21629,21630,21631,21632,21633,21634,21635,21636,21637,
8205821638,21639,21640,21641,21642,21643,21644,21645,21646,21647,21648,21649,
8205921650,21651,21652,21653,21654,21655,21656,21657,21658,21659,21660,21661,
8206021662,21663,21664,21665,21666,21667,21668,21669,21670,21671,21672,21673,
8206121674,21675,21676,21677,21678,21679,21680,21681,21682,21683,21684,21685,
8206221686,21687,21688,21689,21690,21691,21692,21693,21694,21695,21696,21697,
8206321698,21699,21700,21701,21702,21703,21704,21705,21706,21707,21708,21709,
8206421710,21711,21712,21713,21714,21715,21716,21717,21718,21719,21720,21721,
8206521722,21723,21724,21725,21726,21727,21728,21729,21730,21731,21732,21733,
8206621734,21735,21736,21737,21738,21739,21740,21741,21742,21743,21744,21745,
8206721746,21747,21748,21749,21750,21751,21752,21753,21754,21755,21756,21757,
8206821758,21759,21760,21761,21762,21763,21764,21765,21766,21767,21768,21769,
8206921770,21771,21772,21773,21774,21775,21776,21777,21778,21779,21780,21781,
8207021782,21783,21784,21785,21786,21787,21788,21789,21790,21791,21792,21793,
8207121794,21795,21796,21797,21798,21799,21800,21801,21802,21803,21804,21805,
8207221806,21807,21808,21809,21810,21811,21812,21813,21814,21815,21816,21817,
8207321818,21819,21820,21821,21822,21823,21824,21825,21826,21827,21828,21829,
8207421830,21831,21832,21833,21834,21835,21836,21837,21838,21839,21840,21841,
8207521842,21843,21844,21845,21846,21847,21848,21849,21850,21851,21852,21853,
8207621854,21855,21856,21857,21858,21859,21860,21861,21862,21863,21864,21865,
8207721866,21867,21868,21869,21870,21871,21872,21873,21874,21875,21876,21877,
8207821878,21879,21880,21881,21882,21883,21884,21885,21886,21887,21888,21889,
8207921890,21891,21892,21893,21894,21895,21896,21897,21898,21899,21900,21901,
8208021902,21903,21904,21905,21906,21907,21908,21909,21910,21911,21912,21913,
8208121914,21915,21916,21917,21918,21919,21920,21921,21922,21923,21924,21925,
8208221926,21927,21928,21929,21930,21931,21932,21933,21934,21935,21936,21937,
8208321938,21939,21940,21941,21942,21943,21944,21945,21946,21947,21948,21949,
8208421950,21951,21952,21953,21954,21955,21956,21957,21958,21959,21960,21961,
8208521962,21963,21964,21965,21966,21967,21968,21969,21970,21971,21972,21973,
8208621974,21975,21976,21977,21978,21979,21980,21981,21982,21983,21984,21985,
8208721986,21987,21988,21989,21990,21991,21992,21993,21994,21995,21996,21997,
8208821998,21999,22000,22001,22002,22003,22004,22005,22006,22007,22008,22009,
8208922010,22011,22012,22013,22014,22015,22016,22017,22018,22019,22020,22021,
8209022022,22023,22024,22025,22026,22027,22028,22029,22030,22031,22032,22033,
8209122034,22035,22036,22037,22038,22039,22040,22041,22042,22043,22044,22045,
8209222046,22047,22048,22049,22050,22051,22052,22053,22054,22055,22056,22057,
8209322058,22059,22060,22061,22062,22063,22064,22065,22066,22067,22068,22069,
8209422070,22071,22072,22073,22074,22075,22076,22077,22078,22079,22080,22081,
8209522082,22083,22084,22085,22086,22087,22088,22089,22090,22091,22092,22093,
8209622094,22095,22096,22097,22098,22099,22100,22101,22102,22103,22104,22105,
8209722106,22107,22108,22109,22110,22111,22112,22113,22114,22115,22116,22117,
8209822118,22119,22120,22121,22122,22123,22124,22125,22126,22127,22128,22129,
8209922130,22131,22132,22133,22134,22135,22136,22137,22138,22139,22140,22141,
8210022142,22143,22144,22145,22146,22147,22148,22149,22150,22151,22152,22153,
8210122154,22155,22156,22157,22158,22159,22160,22161,22162,22163,22164,22165,
8210222166,22167,22168,22169,22170,22171,22172,22173,22174,22175,22176,22177,
8210322178,22179,22180,22181,22182,22183,22184,22185,22186,22187,22188,22189,
8210422190,22191,22192,22193,22194,22195,22196,22197,22198,22199,22200,22201,
8210522202,22203,22204,22205,22206,22207,22208,22209,22210,22211,22212,22213,
8210622214,22215,22216,22217,22218,22219,22220,22221,22222,22223,22224,22225,
8210722226,22227,22228,22229,22230,22231,22232,22233,22234,22235,22236,22237,
8210822238,22239,22240,22241,22242,22243,22244,22245,22246,22247,22248,22249,
8210922250,22251,22252,22253,22254,22255,22256,22257,22258,22259,22260,22261,
8211022262,22263,22264,22265,22266,22267,22268,22269,22270,22271,22272,22273,
8211122274,22275,22276,22277,22278,22279,22280,22281,22282,22283,22284,22285,
8211222286,22287,22288,22289,22290,22291,22292,22293,22294,22295,22296,22297,
8211322298,22299,22300,22301,22302,22303,22304,22305,22306,22307,22308,22309,
8211422310,22311,22312,22313,22314,22315,22316,22317,22318,22319,22320,22321,
8211522322,22323,22324,22325,22326,22327,22328,22329,22330,22331,22332,22333,
8211622334,22335,22336,22337,22338,22339,22340,22341,22342,22343,22344,22345,
8211722346,22347,22348,22349,22350,22351,22352,22353,22354,22355,22356,22357,
8211822358,22359,22360,22361,22362,22363,22364,22365,22366,22367,22368,22369,
8211922370,22371,22372,22373,22374,22375,22376,22377,22378,22379,22380,22381,
8212022382,22383,22384,22385,22386,22387,22388,22389,22390,22391,22392,22393,
8212122394,22395,22396,22397,22398,22399,22400,22401,22402,22403,22404,22405,
8212222406,22407,22408,22409,22410,22411,22412,22413,22414,22415,22416,22417,
8212322418,22419,22420,22421,22422,22423,22424,22425,22426,22427,22428,22429,
8212422430,22431,22432,22433,22434,22435,22436,22437,22438,22439,22440,22441,
8212522442,22443,22444,22445,22446,22447,22448,22449,22450,22451,22452,22453,
8212622454,22455,22456,22457,22458,22459,22460,22461,22462,22463,22464,22465,
8212722466,22467,22468,22469,22470,22471,22472,22473,22474,22475,22476,22477,
8212822478,22479,22480,22481,22482,22483,22484,22485,22486,22487,22488,22489,
8212922490,22491,22492,22493,22494,22495,22496,22497,22498,22499,22500,22501,
8213022502,22503,22504,22505,22506,22507,22508,22509,22510,22511,22512,22513,
8213122514,22515,22516,22517,22518,22519,22520,22521,22522,22523,22524,22525,
8213222526,22527,22528,22529,22530,22531,22532,22533,22534,22535,22536,22537,
8213322538,22539,22540,22541,22542,22543,22544,22545,22546,22547,22548,22549,
8213422550,22551,22552,22553,22554,22555,22556,22557,22558,22559,22560,22561,
8213522562,22563,22564,22565,22566,22567,22568,22569,22570,22571,22572,22573,
8213622574,22575,22576,22577,22578,22579,22580,22581,22582,22583,22584,22585,
8213722586,22587,22588,22589,22590,22591,22592,22593,22594,22595,22596,22597,
8213822598,22599,22600,22601,22602,22603,22604,22605,22606,22607,22608,22609,
8213922610,22611,22612,22613,22614,22615,22616,22617,22618,22619,22620,22621,
8214022622,22623,22624,22625,22626,22627,22628,22629,22630,22631,22632,22633,
8214122634,22635,22636,22637,22638,22639,22640,22641,22642,22643,22644,22645,
8214222646,22647,22648,22649,22650,22651,22652,22653,22654,22655,22656,22657,
8214322658,22659,22660,22661,22662,22663,22664,22665,22666,22667,22668,22669,
8214422670,22671,22672,22673,22674,22675,22676,22677,22678,22679,22680,22681,
8214522682,22683,22684,22685,22686,22687,22688,22689,22690,22691,22692,22693,
8214622694,22695,22696,22697,22698,22699,22700,22701,22702,22703,22704,22705,
8214722706,22707,22708,22709,22710,22711,22712,22713,22714,22715,22716,22717,
8214822718,22719,22720,22721,22722,22723,22724,22725,22726,22727,22728,22729,
8214922730,22731,22732,22733,22734,22735,22736,22737,22738,22739,22740,22741,
8215022742,22743,22744,22745,22746,22747,22748,22749,22750,22751,22752,22753,
8215122754,22755,22756,22757,22758,22759,22760,22761,22762,22763,22764,22765,
8215222766,22767,22768,22769,22770,22771,22772,22773,22774,22775,22776,22777,
8215322778,22779,22780,22781,22782,22783,22784,22785,22786,22787,22788,22789,
8215422790,22791,22792,22793,22794,22795,22796,22797,22798,22799,22800,22801,
8215522802,22803,22804,22805,22806,22807,22808,22809,22810,22811,22812,22813,
8215622814,22815,22816,22817,22818,22819,22820,22821,22822,22823,22824,22825,
8215722826,22827,22828,22829,22830,22831,22832,22833,22834,22835,22836,22837,
8215822838,22839,22840,22841,22842,22843,22844,22845,22846,22847,22848,22849,
8215922850,22851,22852,22853,22854,22855,22856,22857,22858,22859,22860,22861,
8216022862,22863,22864,22865,22866,22867,22868,22869,22870,22871,22872,22873,
8216122874,22875,22876,22877,22878,22879,22880,22881,22882,22883,22884,22885,
8216222886,22887,22888,22889,22890,22891,22892,22893,22894,22895,22896,22897,
8216322898,22899,22900,22901,22902,22903,22904,22905,22906,22907,22908,22909,
8216422910,22911,22912,22913,22914,22915,22916,22917,22918,22919,22920,22921,
8216522922,22923,22924,22925,22926,22927,22928,22929,22930,22931,22932,22933,
8216622934,22935,22936,22937,22938,22939,22940,22941,22942,22943,22944,22945,
8216722946,22947,22948,22949,22950,22951,22952,22953,22954,22955,22956,22957,
8216822958,22959,22960,22961,22962,22963,22964,22965,22966,22967,22968,22969,
8216922970,22971,22972,22973,22974,22975,22976,22977,22978,22979,22980,22981,
8217022982,22983,22984,22985,22986,22987,22988,22989,22990,22991,22992,22993,
8217122994,22995,22996,22997,22998,22999,23000,23001,23002,23003,23004,23005,
8217223006,23007,23008,23009,23010,23011,23012,23013,23014,23015,23016,23017,
8217323018,23019,23020,23021,23022,23023,23024,23025,23026,23027,23028,23029,
8217423030,23031,23032,23033,23034,23035,23036,23037,23038,23039,23040,23041,
8217523042,23043,23044,23045,23046,23047,23048,23049,23050,23051,23052,23053,
8217623054,23055,23056,23057,23058,23059,23060,23061,23062,23063,23064,23065,
8217723066,23067,23068,23069,23070,23071,23072,23073,23074,23075,23076,23077,
8217823078,23079,23080,23081,23082,23083,23084,23085,23086,23087,23088,23089,
8217923090,23091,23092,23093,23094,23095,23096,23097,23098,23099,23100,23101,
8218023102,23103,23104,23105,23106,23107,23108,23109,23110,23111,23112,23113,
8218123114,23115,23116,23117,23118,23119,23120,23121,23122,23123,23124,23125,
8218223126,23127,23128,23129,23130,23131,23132,23133,23134,23135,23136,23137,
8218323138,23139,23140,23141,23142,23143,23144,23145,23146,23147,23148,23149,
8218423150,23151,23152,23153,23154,23155,23156,23157,23158,23159,23160,23161,
8218523162,23163,23164,23165,23166,23167,23168,23169,23170,23171,23172,23173,
8218623174,23175,23176,23177,23178,23179,23180,23181,23182,23183,23184,23185,
8218723186,23187,23188,23189,23190,23191,23192,23193,23194,23195,23196,23197,
8218823198,23199,23200,23201,23202,23203,23204,23205,23206,23207,23208,23209,
8218923210,23211,23212,23213,23214,23215,23216,23217,23218,23219,23220,23221,
8219023222,23223,23224,23225,23226,23227,23228,23229,23230,23231,23232,23233,
8219123234,23235,23236,23237,23238,23239,23240,23241,23242,23243,23244,23245,
8219223246,23247,23248,23249,23250,23251,23252,23253,23254,23255,23256,23257,
8219323258,23259,23260,23261,23262,23263,23264,23265,23266,23267,23268,23269,
8219423270,23271,23272,23273,23274,23275,23276,23277,23278,23279,23280,23281,
8219523282,23283,23284,23285,23286,23287,23288,23289,23290,23291,23292,23293,
8219623294,23295,23296,23297,23298,23299,23300,23301,23302,23303,23304,23305,
8219723306,23307,23308,23309,23310,23311,23312,23313,23314,23315,23316,23317,
8219823318,23319,23320,23321,23322,23323,23324,23325,23326,23327,23328,23329,
8219923330,23331,23332,23333,23334,23335,23336,23337,23338,23339,23340,23341,
8220023342,23343,23344,23345,23346,23347,23348,23349,23350,23351,23352,23353,
8220123354,23355,23356,23357,23358,23359,23360,23361,23362,23363,23364,23365,
8220223366,23367,23368,23369,23370,23371,23372,23373,23374,23375,23376,23377,
8220323378,23379,23380,23381,23382,23383,23384,23385,23386,23387,23388,23389,
8220423390,23391,23392,23393,23394,23395,23396,23397,23398,23399,23400,23401,
8220523402,23403,23404,23405,23406,23407,23408,23409,23410,23411,23412,23413,
8220623414,23415,23416,23417,23418,23419,23420,23421,23422,23423,23424,23425,
8220723426,23427,23428,23429,23430,23431,23432,23433,23434,23435,23436,23437,
8220823438,23439,23440,23441,23442,23443,23444,23445,23446,23447,23448,23449,
8220923450,23451,23452,23453,23454,23455,23456,23457,23458,23459,23460,23461,
8221023462,23463,23464,23465,23466,23467,23468,23469,23470,23471,23472,23473,
8221123474,23475,23476,23477,23478,23479,23480,23481,23482,23483,23484,23485,
8221223486,23487,23488,23489,23490,23491,23492,23493,23494,23495,23496,23497,
8221323498,23499,23500,23501,23502,23503,23504,23505,23506,23507,23508,23509,
8221423510,23511,23512,23513,23514,23515,23516,23517,23518,23519,23520,23521,
8221523522,23523,23524,23525,23526,23527,23528,23529,23530,23531,23532,23533,
8221623534,23535,23536,23537,23538,23539,23540,23541,23542,23543,23544,23545,
8221723546,23547,23548,23549,23550,23551,23552,23553,23554,23555,23556,23557,
8221823558,23559,23560,23561,23562,23563,23564,23565,23566,23567,23568,23569,
8221923570,23571,23572,23573,23574,23575,23576,23577,23578,23579,23580,23581,
8222023582,23583,23584,23585,23586,23587,23588,23589,23590,23591,23592,23593,
8222123594,23595,23596,23597,23598,23599,23600,23601,23602,23603,23604,23605,
8222223606,23607,23608,23609,23610,23611,23612,23613,23614,23615,23616,23617,
8222323618,23619,23620,23621,23622,23623,23624,23625,23626,23627,23628,23629,
8222423630,23631,23632,23633,23634,23635,23636,23637,23638,23639,23640,23641,
8222523642,23643,23644,23645,23646,23647,23648,23649,23650,23651,23652,23653,
8222623654,23655,23656,23657,23658,23659,23660,23661,23662,23663,23664,23665,
8222723666,23667,23668,23669,23670,23671,23672,23673,23674,23675,23676,23677,
8222823678,23679,23680,23681,23682,23683,23684,23685,23686,23687,23688,23689,
8222923690,23691,23692,23693,23694,23695,23696,23697,23698,23699,23700,23701,
8223023702,23703,23704,23705,23706,23707,23708,23709,23710,23711,23712,23713,
8223123714,23715,23716,23717,23718,23719,23720,23721,23722,23723,23724,23725,
8223223726,23727,23728,23729,23730,23731,23732,23733,23734,23735,23736,23737,
8223323738,23739,23740,23741,23742,23743,23744,23745,23746,23747,23748,23749,
8223423750,23751,23752,23753,23754,23755,23756,23757,23758,23759,23760,23761,
8223523762,23763,23764,23765,23766,23767,23768,23769,23770,23771,23772,23773,
8223623774,23775,23776,23777,23778,23779,23780,23781,23782,23783,23784,23785,
8223723786,23787,23788,23789,23790,23791,23792,23793,23794,23795,23796,23797,
8223823798,23799,23800,23801,23802,23803,23804,23805,23806,23807,23808,23809,
8223923810,23811,23812,23813,23814,23815,23816,23817,23818,23819,23820,23821,
8224023822,23823,23824,23825,23826,23827,23828,23829,23830,23831,23832,23833,
8224123834,23835,23836,23837,23838,23839,23840,23841,23842,23843,23844,23845,
8224223846,23847,23848,23849,23850,23851,23852,23853,23854,23855,23856,23857,
8224323858,23859,23860,23861,23862,23863,23864,23865,23866,23867,23868,23869,
8224423870,23871,23872,23873,23874,23875,23876,23877,23878,23879,23880,23881,
8224523882,23883,23884,23885,23886,23887,23888,23889,23890,23891,23892,23893,
8224623894,23895,23896,23897,23898,23899,23900,23901,23902,23903,23904,23905,
8224723906,23907,23908,23909,23910,23911,23912,23913,23914,23915,23916,23917,
8224823918,23919,23920,23921,23922,23923,23924,23925,23926,23927,23928,23929,
8224923930,23931,23932,23933,23934,23935,23936,23937,23938,23939,23940,23941,
8225023942,23943,23944,23945,23946,23947,23948,23949,23950,23951,23952,23953,
8225123954,23955,23956,23957,23958,23959,23960,23961,23962,23963,23964,23965,
8225223966,23967,23968,23969,23970,23971,23972,23973,23974,23975,23976,23977,
8225323978,23979,23980,23981,23982,23983,23984,23985,23986,23987,23988,23989,
8225423990,23991,23992,23993,23994,23995,23996,23997,23998,23999,24000,24001,
8225524002,24003,24004,24005,24006,24007,24008,24009,24010,24011,24012,24013,
8225624014,24015,24016,24017,24018,24019,24020,24021,24022,24023,24024,24025,
8225724026,24027,24028,24029,24030,24031,24032,24033,24034,24035,24036,24037,
8225824038,24039,24040,24041,24042,24043,24044,24045,24046,24047,24048,24049,
8225924050,24051,24052,24053,24054,24055,24056,24057,24058,24059,24060,24061,
8226024062,24063,24064,24065,24066,24067,24068,24069,24070,24071,24072,24073,
8226124074,24075,24076,24077,24078,24079,24080,24081,24082,24083,24084,24085,
8226224086,24087,24088,24089,24090,24091,24092,24093,24094,24095,24096,24097,
8226324098,24099,24100,24101,24102,24103,24104,24105,24106,24107,24108,24109,
8226424110,24111,24112,24113,24114,24115,24116,24117,24118,24119,24120,24121,
8226524122,24123,24124,24125,24126,24127,24128,24129,24130,24131,24132,24133,
8226624134,24135,24136,24137,24138,24139,24140,24141,24142,24143,24144,24145,
8226724146,24147,24148,24149,24150,24151,24152,24153,24154,24155,24156,24157,
8226824158,24159,24160,24161,24162,24163,24164,24165,24166,24167,24168,24169,
8226924170,24171,24172,24173,24174,24175,24176,24177,24178,24179,24180,24181,
8227024182,24183,24184,24185,24186,24187,24188,24189,24190,24191,24192,24193,
8227124194,24195,24196,24197,24198,24199,24200,24201,24202,24203,24204,24205,
8227224206,24207,24208,24209,24210,24211,24212,24213,24214,24215,24216,24217,
8227324218,24219,24220,24221,24222,24223,24224,24225,24226,24227,24228,24229,
8227424230,24231,24232,24233,24234,24235,24236,24237,24238,24239,24240,24241,
8227524242,24243,24244,24245,24246,24247,24248,24249,24250,24251,24252,24253,
8227624254,24255,24256,24257,24258,24259,24260,24261,24262,24263,24264,24265,
8227724266,24267,24268,24269,24270,24271,24272,24273,24274,24275,24276,24277,
8227824278,24279,24280,24281,24282,24283,24284,24285,24286,24287,24288,24289,
8227924290,24291,24292,24293,24294,24295,24296,24297,24298,24299,24300,24301,
8228024302,24303,24304,24305,24306,24307,24308,24309,24310,24311,24312,24313,
8228124314,24315,24316,24317,24318,24319,24320,24321,24322,24323,24324,24325,
8228224326,24327,24328,24329,24330,24331,24332,24333,24334,24335,24336,24337,
8228324338,24339,24340,24341,24342,24343,24344,24345,24346,24347,24348,24349,
8228424350,24351,24352,24353,24354,24355,24356,24357,24358,24359,24360,24361,
8228524362,24363,24364,24365,24366,24367,24368,24369,24370,24371,24372,24373,
8228624374,24375,24376,24377,24378,24379,24380,24381,24382,24383,24384,24385,
8228724386,24387,24388,24389,24390,24391,24392,24393,24394,24395,24396,24397,
8228824398,24399,24400,24401,24402,24403,24404,24405,24406,24407,24408,24409,
8228924410,24411,24412,24413,24414,24415,24416,24417,24418,24419,24420,24421,
8229024422,24423,24424,24425,24426,24427,24428,24429,24430,24431,24432,24433,
8229124434,24435,24436,24437,24438,24439,24440,24441,24442,24443,24444,24445,
8229224446,24447,24448,24449,24450,24451,24452,24453,24454,24455,24456,24457,
8229324458,24459,24460,24461,24462,24463,24464,24465,24466,24467,24468,24469,
8229424470,24471,24472,24473,24474,24475,24476,24477,24478,24479,24480,24481,
8229524482,24483,24484,24485,24486,24487,24488,24489,24490,24491,24492,24493,
8229624494,24495,24496,24497,24498,24499,24500,24501,24502,24503,24504,24505,
8229724506,24507,24508,24509,24510,24511,24512,24513,24514,24515,24516,24517,
8229824518,24519,24520,24521,24522,24523,24524,24525,24526,24527,24528,24529,
8229924530,24531,24532,24533,24534,24535,24536,24537,24538,24539,24540,24541,
8230024542,24543,24544,24545,24546,24547,24548,24549,24550,24551,24552,24553,
8230124554,24555,24556,24557,24558,24559,24560,24561,24562,24563,24564,24565,
8230224566,24567,24568,24569,24570,24571,24572,24573,24574,24575,24576,24577,
8230324578,24579,24580,24581,24582,24583,24584,24585,24586,24587,24588,24589,
8230424590,24591,24592,24593,24594,24595,24596,24597,24598,24599,24600,24601,
8230524602,24603,24604,24605,24606,24607,24608,24609,24610,24611,24612,24613,
8230624614,24615,24616,24617,24618,24619,24620,24621,24622,24623,24624,24625,
8230724626,24627,24628,24629,24630,24631,24632,24633,24634,24635,24636,24637,
8230824638,24639,24640,24641,24642,24643,24644,24645,24646,24647,24648,24649,
8230924650,24651,24652,24653,24654,24655,24656,24657,24658,24659,24660,24661,
8231024662,24663,24664,24665,24666,24667,24668,24669,24670,24671,24672,24673,
8231124674,24675,24676,24677,24678,24679,24680,24681,24682,24683,24684,24685,
8231224686,24687,24688,24689,24690,24691,24692,24693,24694,24695,24696,24697,
8231324698,24699,24700,24701,24702,24703,24704,24705,24706,24707,24708,24709,
8231424710,24711,24712,24713,24714,24715,24716,24717,24718,24719,24720,24721,
8231524722,24723,24724,24725,24726,24727,24728,24729,24730,24731,24732,24733,
8231624734,24735,24736,24737,24738,24739,24740,24741,24742,24743,24744,24745,
8231724746,24747,24748,24749,24750,24751,24752,24753,24754,24755,24756,24757,
8231824758,24759,24760,24761,24762,24763,24764,24765,24766,24767,24768,24769,
8231924770,24771,24772,24773,24774,24775,24776,24777,24778,24779,24780,24781,
8232024782,24783,24784,24785,24786,24787,24788,24789,24790,24791,24792,24793,
8232124794,24795,24796,24797,24798,24799,24800,24801,24802,24803,24804,24805,
8232224806,24807,24808,24809,24810,24811,24812,24813,24814,24815,24816,24817,
8232324818,24819,24820,24821,24822,24823,24824,24825,24826,24827,24828,24829,
8232424830,24831,24832,24833,24834,24835,24836,24837,24838,24839,24840,24841,
8232524842,24843,24844,24845,24846,24847,24848,24849,24850,24851,24852,24853,
8232624854,24855,24856,24857,24858,24859,24860,24861,24862,24863,24864,24865,
8232724866,24867,24868,24869,24870,24871,24872,24873,24874,24875,24876,24877,
8232824878,24879,24880,24881,24882,24883,24884,24885,24886,24887,24888,24889,
8232924890,24891,24892,24893,24894,24895,24896,24897,24898,24899,24900,24901,
8233024902,24903,24904,24905,24906,24907,24908,24909,24910,24911,24912,24913,
8233124914,24915,24916,24917,24918,24919,24920,24921,24922,24923,24924,24925,
8233224926,24927,24928,24929,24930,24931,24932,24933,24934,24935,24936,24937,
8233324938,24939,24940,24941,24942,24943,24944,24945,24946,24947,24948,24949,
8233424950,24951,24952,24953,24954,24955,24956,24957,24958,24959,24960,24961,
8233524962,24963,24964,24965,24966,24967,24968,24969,24970,24971,24972,24973,
8233624974,24975,24976,24977,24978,24979,24980,24981,24982,24983,24984,24985,
8233724986,24987,24988,24989,24990,24991,24992,24993,24994,24995,24996,24997,
8233824998,24999,25000,25001,25002,25003,25004,25005,25006,25007,25008,25009,
8233925010,25011,25012,25013,25014,25015,25016,25017,25018,25019,25020,25021,
8234025022,25023,25024,25025,25026,25027,25028,25029,25030,25031,25032,25033,
8234125034,25035,25036,25037,25038,25039,25040,25041,25042,25043,25044,25045,
8234225046,25047,25048,25049,25050,25051,25052,25053,25054,25055,25056,25057,
8234325058,25059,25060,25061,25062,25063,25064,25065,25066,25067,25068,25069,
8234425070,25071,25072,25073,25074,25075,25076,25077,25078,25079,25080,25081,
8234525082,25083,25084,25085,25086,25087,25088,25089,25090,25091,25092,25093,
8234625094,25095,25096,25097,25098,25099,25100,25101,25102,25103,25104,25105,
8234725106,25107,25108,25109,25110,25111,25112,25113,25114,25115,25116,25117,
8234825118,25119,25120,25121,25122,25123,25124,25125,25126,25127,25128,25129,
8234925130,25131,25132,25133,25134,25135,25136,25137,25138,25139,25140,25141,
8235025142,25143,25144,25145,25146,25147,25148,25149,25150,25151,25152,25153,
8235125154,25155,25156,25157,25158,25159,25160,25161,25162,25163,25164,25165,
8235225166,25167,25168,25169,25170,25171,25172,25173,25174,25175,25176,25177,
8235325178,25179,25180,25181,25182,25183,25184,25185,25186,25187,25188,25189,
8235425190,25191,25192,25193,25194,25195,25196,25197,25198,25199,25200,25201,
8235525202,25203,25204,25205,25206,25207,25208,25209,25210,25211,25212,25213,
8235625214,25215,25216,25217,25218,25219,25220,25221,25222,25223,25224,25225,
8235725226,25227,25228,25229,25230,25231,25232,25233,25234,25235,25236,25237,
8235825238,25239,25240,25241,25242,25243,25244,25245,25246,25247,25248,25249,
8235925250,25251,25252,25253,25254,25255,25256,25257,25258,25259,25260,25261,
8236025262,25263,25264,25265,25266,25267,25268,25269,25270,25271,25272,25273,
8236125274,25275,25276,25277,25278,25279,25280,25281,25282,25283,25284,25285,
8236225286,25287,25288,25289,25290,25291,25292,25293,25294,25295,25296,25297,
8236325298,25299,25300,25301,25302,25303,25304,25305,25306,25307,25308,25309,
8236425310,25311,25312,25313,25314,25315,25316,25317,25318,25319,25320,25321,
8236525322,25323,25324,25325,25326,25327,25328,25329,25330,25331,25332,25333,
8236625334,25335,25336,25337,25338,25339,25340,25341,25342,25343,25344,25345,
8236725346,25347,25348,25349,25350,25351,25352,25353,25354,25355,25356,25357,
8236825358,25359,25360,25361,25362,25363,25364,25365,25366,25367,25368,25369,
8236925370,25371,25372,25373,25374,25375,25376,25377,25378,25379,25380,25381,
8237025382,25383,25384,25385,25386,25387,25388,25389,25390,25391,25392,25393,
8237125394,25395,25396,25397,25398,25399,25400,25401,25402,25403,25404,25405,
8237225406,25407,25408,25409,25410,25411,25412,25413,25414,25415,25416,25417,
8237325418,25419,25420,25421,25422,25423,25424,25425,25426,25427,25428,25429,
8237425430,25431,25432,25433,25434,25435,25436,25437,25438,25439,25440,25441,
8237525442,25443,25444,25445,25446,25447,25448,25449,25450,25451,25452,25453,
8237625454,25455,25456,25457,25458,25459,25460,25461,25462,25463,25464,25465,
8237725466,25467,25468,25469,25470,25471,25472,25473,25474,25475,25476,25477,
8237825478,25479,25480,25481,25482,25483,25484,25485,25486,25487,25488,25489,
8237925490,25491,25492,25493,25494,25495,25496,25497,25498,25499,25500,25501,
8238025502,25503,25504,25505,25506,25507,25508,25509,25510,25511,25512,25513,
8238125514,25515,25516,25517,25518,25519,25520,25521,25522,25523,25524,25525,
8238225526,25527,25528,25529,25530,25531,25532,25533,25534,25535,25536,25537,
8238325538,25539,25540,25541,25542,25543,25544,25545,25546,25547,25548,25549,
8238425550,25551,25552,25553,25554,25555,25556,25557,25558,25559,25560,25561,
8238525562,25563,25564,25565,25566,25567,25568,25569,25570,25571,25572,25573,
8238625574,25575,25576,25577,25578,25579,25580,25581,25582,25583,25584,25585,
8238725586,25587,25588,25589,25590,25591,25592,25593,25594,25595,25596,25597,
8238825598,25599,25600,25601,25602,25603,25604,25605,25606,25607,25608,25609,
8238925610,25611,25612,25613,25614,25615,25616,25617,25618,25619,25620,25621,
8239025622,25623,25624,25625,25626,25627,25628,25629,25630,25631,25632,25633,
8239125634,25635,25636,25637,25638,25639,25640,25641,25642,25643,25644,25645,
8239225646,25647,25648,25649,25650,25651,25652,25653,25654,25655,25656,25657,
8239325658,25659,25660,25661,25662,25663,25664,25665,25666,25667,25668,25669,
8239425670,25671,25672,25673,25674,25675,25676,25677,25678,25679,25680,25681,
8239525682,25683,25684,25685,25686,25687,25688,25689,25690,25691,25692,25693,
8239625694,25695,25696,25697,25698,25699,25700,25701,25702,25703,25704,25705,
8239725706,25707,25708,25709,25710,25711,25712,25713,25714,25715,25716,25717,
8239825718,25719,25720,25721,25722,25723,25724,25725,25726,25727,25728,25729,
8239925730,25731,25732,25733,25734,25735,25736,25737,25738,25739,25740,25741,
8240025742,25743,25744,25745,25746,25747,25748,25749,25750,25751,25752,25753,
8240125754,25755,25756,25757,25758,25759,25760,25761,25762,25763,25764,25765,
8240225766,25767,25768,25769,25770,25771,25772,25773,25774,25775,25776,25777,
8240325778,25779,25780,25781,25782,25783,25784,25785,25786,25787,25788,25789,
8240425790,25791,25792,25793,25794,25795,25796,25797,25798,25799,25800,25801,
8240525802,25803,25804,25805,25806,25807,25808,25809,25810,25811,25812,25813,
8240625814,25815,25816,25817,25818,25819,25820,25821,25822,25823,25824,25825,
8240725826,25827,25828,25829,25830,25831,25832,25833,25834,25835,25836,25837,
8240825838,25839,25840,25841,25842,25843,25844,25845,25846,25847,25848,25849,
8240925850,25851,25852,25853,25854,25855,25856,25857,25858,25859,25860,25861,
8241025862,25863,25864,25865,25866,25867,25868,25869,25870,25871,25872,25873,
8241125874,25875,25876,25877,25878,25879,25880,25881,25882,25883,25884,25885,
8241225886,25887,25888,25889,25890,25891,25892,25893,25894,25895,25896,25897,
8241325898,25899,25900,25901,25902,25903,25904,25905,25906,25907,25908,25909,
8241425910,25911,25912,25913,25914,25915,25916,25917,25918,25919,25920,25921,
8241525922,25923,25924,25925,25926,25927,25928,25929,25930,25931,25932,25933,
8241625934,25935,25936,25937,25938,25939,25940,25941,25942,25943,25944,25945,
8241725946,25947,25948,25949,25950,25951,25952,25953,25954,25955,25956,25957,
8241825958,25959,25960,25961,25962,25963,25964,25965,25966,25967,25968,25969,
8241925970,25971,25972,25973,25974,25975,25976,25977,25978,25979,25980,25981,
8242025982,25983,25984,25985,25986,25987,25988,25989,25990,25991,25992,25993,
8242125994,25995,25996,25997,25998,25999,26000,26001,26002,26003,26004,26005,
8242226006,26007,26008,26009,26010,26011,26012,26013,26014,26015,26016,26017,
8242326018,26019,26020,26021,26022,26023,26024,26025,26026,26027,26028,26029,
8242426030,26031,26032,26033,26034,26035,26036,26037,26038,26039,26040,26041,
8242526042,26043,26044,26045,26046,26047,26048,26049,26050,26051,26052,26053,
8242626054,26055,26056,26057,26058,26059,26060,26061,26062,26063,26064,26065,
8242726066,26067,26068,26069,26070,26071,26072,26073,26074,26075,26076,26077,
8242826078,26079,26080,26081,26082,26083,26084,26085,26086,26087,26088,26089,
8242926090,26091,26092,26093,26094,26095,26096,26097,26098,26099,26100,26101,
8243026102,26103,26104,26105,26106,26107,26108,26109,26110,26111,26112,26113,
8243126114,26115,26116,26117,26118,26119,26120,26121,26122,26123,26124,26125,
8243226126,26127,26128,26129,26130,26131,26132,26133,26134,26135,26136,26137,
8243326138,26139,26140,26141,26142,26143,26144,26145,26146,26147,26148,26149,
8243426150,26151,26152,26153,26154,26155,26156,26157,26158,26159,26160,26161,
8243526162,26163,26164,26165,26166,26167,26168,26169,26170,26171,26172,26173,
8243626174,26175,26176,26177,26178,26179,26180,26181,26182,26183,26184,26185,
8243726186,26187,26188,26189,26190,26191,26192,26193,26194,26195,26196,26197,
8243826198,26199,26200,26201,26202,26203,26204,26205,26206,26207,26208,26209,
8243926210,26211,26212,26213,26214,26215,26216,26217,26218,26219,26220,26221,
8244026222,26223,26224,26225,26226,26227,26228,26229,26230,26231,26232,26233,
8244126234,26235,26236,26237,26238,26239,26240,26241,26242,26243,26244,26245,
8244226246,26247,26248,26249,26250,26251,26252,26253,26254,26255,26256,26257,
8244326258,26259,26260,26261,26262,26263,26264,26265,26266,26267,26268,26269,
8244426270,26271,26272,26273,26274,26275,26276,26277,26278,26279,26280,26281,
8244526282,26283,26284,26285,26286,26287,26288,26289,26290,26291,26292,26293,
8244626294,26295,26296,26297,26298,26299,26300,26301,26302,26303,26304,26305,
8244726306,26307,26308,26309,26310,26311,26312,26313,26314,26315,26316,26317,
8244826318,26319,26320,26321,26322,26323,26324,26325,26326,26327,26328,26329,
8244926330,26331,26332,26333,26334,26335,26336,26337,26338,26339,26340,26341,
8245026342,26343,26344,26345,26346,26347,26348,26349,26350,26351,26352,26353,
8245126354,26355,26356,26357,26358,26359,26360,26361,26362,26363,26364,26365,
8245226366,26367,26368,26369,26370,26371,26372,26373,26374,26375,26376,26377,
8245326378,26379,26380,26381,26382,26383,26384,26385,26386,26387,26388,26389,
8245426390,26391,26392,26393,26394,26395,26396,26397,26398,26399,26400,26401,
8245526402,26403,26404,26405,26406,26407,26408,26409,26410,26411,26412,26413,
8245626414,26415,26416,26417,26418,26419,26420,26421,26422,26423,26424,26425,
8245726426,26427,26428,26429,26430,26431,26432,26433,26434,26435,26436,26437,
8245826438,26439,26440,26441,26442,26443,26444,26445,26446,26447,26448,26449,
8245926450,26451,26452,26453,26454,26455,26456,26457,26458,26459,26460,26461,
8246026462,26463,26464,26465,26466,26467,26468,26469,26470,26471,26472,26473,
8246126474,26475,26476,26477,26478,26479,26480,26481,26482,26483,26484,26485,
8246226486,26487,26488,26489,26490,26491,26492,26493,26494,26495,26496,26497,
8246326498,26499,26500,26501,26502,26503,26504,26505,26506,26507,26508,26509,
8246426510,26511,26512,26513,26514,26515,26516,26517,26518,26519,26520,26521,
8246526522,26523,26524,26525,26526,26527,26528,26529,26530,26531,26532,26533,
8246626534,26535,26536,26537,26538,26539,26540,26541,26542,26543,26544,26545,
8246726546,26547,26548,26549,26550,26551,26552,26553,26554,26555,26556,26557,
8246826558,26559,26560,26561,26562,26563,26564,26565,26566,26567,26568,26569,
8246926570,26571,26572,26573,26574,26575,26576,26577,26578,26579,26580,26581,
8247026582,26583,26584,26585,26586,26587,26588,26589,26590,26591,26592,26593,
8247126594,26595,26596,26597,26598,26599,26600,26601,26602,26603,26604,26605,
8247226606,26607,26608,26609,26610,26611,26612,26613,26614,26615,26616,26617,
8247326618,26619,26620,26621,26622,26623,26624,26625,26626,26627,26628,26629,
8247426630,26631,26632,26633,26634,26635,26636,26637,26638,26639,26640,26641,
8247526642,26643,26644,26645,26646,26647,26648,26649,26650,26651,26652,26653,
8247626654,26655,26656,26657,26658,26659,26660,26661,26662,26663,26664,26665,
8247726666,26667,26668,26669,26670,26671,26672,26673,26674,26675,26676,26677,
8247826678,26679,26680,26681,26682,26683,26684,26685,26686,26687,26688,26689,
8247926690,26691,26692,26693,26694,26695,26696,26697,26698,26699,26700,26701,
8248026702,26703,26704,26705,26706,26707,26708,26709,26710,26711,26712,26713,
8248126714,26715,26716,26717,26718,26719,26720,26721,26722,26723,26724,26725,
8248226726,26727,26728,26729,26730,26731,26732,26733,26734,26735,26736,26737,
8248326738,26739,26740,26741,26742,26743,26744,26745,26746,26747,26748,26749,
8248426750,26751,26752,26753,26754,26755,26756,26757,26758,26759,26760,26761,
8248526762,26763,26764,26765,26766,26767,26768,26769,26770,26771,26772,26773,
8248626774,26775,26776,26777,26778,26779,26780,26781,26782,26783,26784,26785,
8248726786,26787,26788,26789,26790,26791,26792,26793,26794,26795,26796,26797,
8248826798,26799,26800,26801,26802,26803,26804,26805,26806,26807,26808,26809,
8248926810,26811,26812,26813,26814,26815,26816,26817,26818,26819,26820,26821,
8249026822,26823,26824,26825,26826,26827,26828,26829,26830,26831,26832,26833,
8249126834,26835,26836,26837,26838,26839,26840,26841,26842,26843,26844,26845,
8249226846,26847,26848,26849,26850,26851,26852,26853,26854,26855,26856,26857,
8249326858,26859,26860,26861,26862,26863,26864,26865,26866,26867,26868,26869,
8249426870,26871,26872,26873,26874,26875,26876,26877,26878,26879,26880,26881,
8249526882,26883,26884,26885,26886,26887,26888,26889,26890,26891,26892,26893,
8249626894,26895,26896,26897,26898,26899,26900,26901,26902,26903,26904,26905,
8249726906,26907,26908,26909,26910,26911,26912,26913,26914,26915,26916,26917,
8249826918,26919,26920,26921,26922,26923,26924,26925,26926,26927,26928,26929,
8249926930,26931,26932,26933,26934,26935,26936,26937,26938,26939,26940,26941,
8250026942,26943,26944,26945,26946,26947,26948,26949,26950,26951,26952,26953,
8250126954,26955,26956,26957,26958,26959,26960,26961,26962,26963,26964,26965,
8250226966,26967,26968,26969,26970,26971,26972,26973,26974,26975,26976,26977,
8250326978,26979,26980,26981,26982,26983,26984,26985,26986,26987,26988,26989,
8250426990,26991,26992,26993,26994,26995,26996,26997,26998,26999,27000,27001,
8250527002,27003,27004,27005,27006,27007,27008,27009,27010,27011,27012,27013,
8250627014,27015,27016,27017,27018,27019,27020,27021,27022,27023,27024,27025,
8250727026,27027,27028,27029,27030,27031,27032,27033,27034,27035,27036,27037,
8250827038,27039,27040,27041,27042,27043,27044,27045,27046,27047,27048,27049,
8250927050,27051,27052,27053,27054,27055,27056,27057,27058,27059,27060,27061,
8251027062,27063,27064,27065,27066,27067,27068,27069,27070,27071,27072,27073,
8251127074,27075,27076,27077,27078,27079,27080,27081,27082,27083,27084,27085,
8251227086,27087,27088,27089,27090,27091,27092,27093,27094,27095,27096,27097,
8251327098,27099,27100,27101,27102,27103,27104,27105,27106,27107,27108,27109,
8251427110,27111,27112,27113,27114,27115,27116,27117,27118,27119,27120,27121,
8251527122,27123,27124,27125,27126,27127,27128,27129,27130,27131,27132,27133,
8251627134,27135,27136,27137,27138,27139,27140,27141,27142,27143,27144,27145,
8251727146,27147,27148,27149,27150,27151,27152,27153,27154,27155,27156,27157,
8251827158,27159,27160,27161,27162,27163,27164,27165,27166,27167,27168,27169,
8251927170,27171,27172,27173,27174,27175,27176,27177,27178,27179,27180,27181,
8252027182,27183,27184,27185,27186,27187,27188,27189,27190,27191,27192,27193,
8252127194,27195,27196,27197,27198,27199,27200,27201,27202,27203,27204,27205,
8252227206,27207,27208,27209,27210,27211,27212,27213,27214,27215,27216,27217,
8252327218,27219,27220,27221,27222,27223,27224,27225,27226,27227,27228,27229,
8252427230,27231,27232,27233,27234,27235,27236,27237,27238,27239,27240,27241,
8252527242,27243,27244,27245,27246,27247,27248,27249,27250,27251,27252,27253,
8252627254,27255,27256,27257,27258,27259,27260,27261,27262,27263,27264,27265,
8252727266,27267,27268,27269,27270,27271,27272,27273,27274,27275,27276,27277,
8252827278,27279,27280,27281,27282,27283,27284,27285,27286,27287,27288,27289,
8252927290,27291,27292,27293,27294,27295,27296,27297,27298,27299,27300,27301,
8253027302,27303,27304,27305,27306,27307,27308,27309,27310,27311,27312,27313,
8253127314,27315,27316,27317,27318,27319,27320,27321,27322,27323,27324,27325,
8253227326,27327,27328,27329,27330,27331,27332,27333,27334,27335,27336,27337,
8253327338,27339,27340,27341,27342,27343,27344,27345,27346,27347,27348,27349,
8253427350,27351,27352,27353,27354,27355,27356,27357,27358,27359,27360,27361,
8253527362,27363,27364,27365,27366,27367,27368,27369,27370,27371,27372,27373,
8253627374,27375,27376,27377,27378,27379,27380,27381,27382,27383,27384,27385,
8253727386,27387,27388,27389,27390,27391,27392,27393,27394,27395,27396,27397,
8253827398,27399,27400,27401,27402,27403,27404,27405,27406,27407,27408,27409,
8253927410,27411,27412,27413,27414,27415,27416,27417,27418,27419,27420,27421,
8254027422,27423,27424,27425,27426,27427,27428,27429,27430,27431,27432,27433,
8254127434,27435,27436,27437,27438,27439,27440,27441,27442,27443,27444,27445,
8254227446,27447,27448,27449,27450,27451,27452,27453,27454,27455,27456,27457,
8254327458,27459,27460,27461,27462,27463,27464,27465,27466,27467,27468,27469,
8254427470,27471,27472,27473,27474,27475,27476,27477,27478,27479,27480,27481,
8254527482,27483,27484,27485,27486,27487,27488,27489,27490,27491,27492,27493,
8254627494,27495,27496,27497,27498,27499,27500,27501,27502,27503,27504,27505,
8254727506,27507,27508,27509,27510,27511,27512,27513,27514,27515,27516,27517,
8254827518,27519,27520,27521,27522,27523,27524,27525,27526,27527,27528,27529,
8254927530,27531,27532,27533,27534,27535,27536,27537,27538,27539,27540,27541,
8255027542,27543,27544,27545,27546,27547,27548,27549,27550,27551,27552,27553,
8255127554,27555,27556,27557,27558,27559,27560,27561,27562,27563,27564,27565,
8255227566,27567,27568,27569,27570,27571,27572,27573,27574,27575,27576,27577,
8255327578,27579,27580,27581,27582,27583,27584,27585,27586,27587,27588,27589,
8255427590,27591,27592,27593,27594,27595,27596,27597,27598,27599,27600,27601,
8255527602,27603,27604,27605,27606,27607,27608,27609,27610,27611,27612,27613,
8255627614,27615,27616,27617,27618,27619,27620,27621,27622,27623,27624,27625,
8255727626,27627,27628,27629,27630,27631,27632,27633,27634,27635,27636,27637,
8255827638,27639,27640,27641,27642,27643,27644,27645,27646,27647,27648,27649,
8255927650,27651,27652,27653,27654,27655,27656,27657,27658,27659,27660,27661,
8256027662,27663,27664,27665,27666,27667,27668,27669,27670,27671,27672,27673,
8256127674,27675,27676,27677,27678,27679,27680,27681,27682,27683,27684,27685,
8256227686,27687,27688,27689,27690,27691,27692,27693,27694,27695,27696,27697,
8256327698,27699,27700,27701,27702,27703,27704,27705,27706,27707,27708,27709,
8256427710,27711,27712,27713,27714,27715,27716,27717,27718,27719,27720,27721,
8256527722,27723,27724,27725,27726,27727,27728,27729,27730,27731,27732,27733,
8256627734,27735,27736,27737,27738,27739,27740,27741,27742,27743,27744,27745,
8256727746,27747,27748,27749,27750,27751,27752,27753,27754,27755,27756,27757,
8256827758,27759,27760,27761,27762,27763,27764,27765,27766,27767,27768,27769,
8256927770,27771,27772,27773,27774,27775,27776,27777,27778,27779,27780,27781,
8257027782,27783,27784,27785,27786,27787,27788,27789,27790,27791,27792,27793,
8257127794,27795,27796,27797,27798,27799,27800,27801,27802,27803,27804,27805,
8257227806,27807,27808,27809,27810,27811,27812,27813,27814,27815,27816,27817,
8257327818,27819,27820,27821,27822,27823,27824,27825,27826,27827,27828,27829,
8257427830,27831,27832,27833,27834,27835,27836,27837,27838,27839,27840,27841,
8257527842,27843,27844,27845,27846,27847,27848,27849,27850,27851,27852,27853,
8257627854,27855,27856,27857,27858,27859,27860,27861,27862,27863,27864,27865,
8257727866,27867,27868,27869,27870,27871,27872,27873,27874,27875,27876,27877,
8257827878,27879,27880,27881,27882,27883,27884,27885,27886,27887,27888,27889,
8257927890,27891,27892,27893,27894,27895,27896,27897,27898,27899,27900,27901,
8258027902,27903,27904,27905,27906,27907,27908,27909,27910,27911,27912,27913,
8258127914,27915,27916,27917,27918,27919,27920,27921,27922,27923,27924,27925,
8258227926,27927,27928,27929,27930,27931,27932,27933,27934,27935,27936,27937,
8258327938,27939,27940,27941,27942,27943,27944,27945,27946,27947,27948,27949,
8258427950,27951,27952,27953,27954,27955,27956,27957,27958,27959,27960,27961,
8258527962,27963,27964,27965,27966,27967,27968,27969,27970,27971,27972,27973,
8258627974,27975,27976,27977,27978,27979,27980,27981,27982,27983,27984,27985,
8258727986,27987,27988,27989,27990,27991,27992,27993,27994,27995,27996,27997,
8258827998,27999,28000,28001,28002,28003,28004,28005,28006,28007,28008,28009,
8258928010,28011,28012,28013,28014,28015,28016,28017,28018,28019,28020,28021,
8259028022,28023,28024,28025,28026,28027,28028,28029,28030,28031,28032,28033,
8259128034,28035,28036,28037,28038,28039,28040,28041,28042,28043,28044,28045,
8259228046,28047,28048,28049,28050,28051,28052,28053,28054,28055,28056,28057,
8259328058,28059,28060,28061,28062,28063,28064,28065,28066,28067,28068,28069,
8259428070,28071,28072,28073,28074,28075,28076,28077,28078,28079,28080,28081,
8259528082,28083,28084,28085,28086,28087,28088,28089,28090,28091,28092,28093,
8259628094,28095,28096,28097,28098,28099,28100,28101,28102,28103,28104,28105,
8259728106,28107,28108,28109,28110,28111,28112,28113,28114,28115,28116,28117,
8259828118,28119,28120,28121,28122,28123,28124,28125,28126,28127,28128,28129,
8259928130,28131,28132,28133,28134,28135,28136,28137,28138,28139,28140,28141,
8260028142,28143,28144,28145,28146,28147,28148,28149,28150,28151,28152,28153,
8260128154,28155,28156,28157,28158,28159,28160,28161,28162,28163,28164,28165,
8260228166,28167,28168,28169,28170,28171,28172,28173,28174,28175,28176,28177,
8260328178,28179,28180,28181,28182,28183,28184,28185,28186,28187,28188,28189,
8260428190,28191,28192,28193,28194,28195,28196,28197,28198,28199,28200,28201,
8260528202,28203,28204,28205,28206,28207,28208,28209,28210,28211,28212,28213,
8260628214,28215,28216,28217,28218,28219,28220,28221,28222,28223,28224,28225,
8260728226,28227,28228,28229,28230,28231,28232,28233,28234,28235,28236,28237,
8260828238,28239,28240,28241,28242,28243,28244,28245,28246,28247,28248,28249,
8260928250,28251,28252,28253,28254,28255,28256,28257,28258,28259,28260,28261,
8261028262,28263,28264,28265,28266,28267,28268,28269,28270,28271,28272,28273,
8261128274,28275,28276,28277,28278,28279,28280,28281,28282,28283,28284,28285,
8261228286,28287,28288,28289,28290,28291,28292,28293,28294,28295,28296,28297,
8261328298,28299,28300,28301,28302,28303,28304,28305,28306,28307,28308,28309,
8261428310,28311,28312,28313,28314,28315,28316,28317,28318,28319,28320,28321,
8261528322,28323,28324,28325,28326,28327,28328,28329,28330,28331,28332,28333,
8261628334,28335,28336,28337,28338,28339,28340,28341,28342,28343,28344,28345,
8261728346,28347,28348,28349,28350,28351,28352,28353,28354,28355,28356,28357,
8261828358,28359,28360,28361,28362,28363,28364,28365,28366,28367,28368,28369,
8261928370,28371,28372,28373,28374,28375,28376,28377,28378,28379,28380,28381,
8262028382,28383,28384,28385,28386,28387,28388,28389,28390,28391,28392,28393,
8262128394,28395,28396,28397,28398,28399,28400,28401,28402,28403,28404,28405,
8262228406,28407,28408,28409,28410,28411,28412,28413,28414,28415,28416,28417,
8262328418,28419,28420,28421,28422,28423,28424,28425,28426,28427,28428,28429,
8262428430,28431,28432,28433,28434,28435,28436,28437,28438,28439,28440,28441,
8262528442,28443,28444,28445,28446,28447,28448,28449,28450,28451,28452,28453,
8262628454,28455,28456,28457,28458,28459,28460,28461,28462,28463,28464,28465,
8262728466,28467,28468,28469,28470,28471,28472,28473,28474,28475,28476,28477,
8262828478,28479,28480,28481,28482,28483,28484,28485,28486,28487,28488,28489,
8262928490,28491,28492,28493,28494,28495,28496,28497,28498,28499,28500,28501,
8263028502,28503,28504,28505,28506,28507,28508,28509,28510,28511,28512,28513,
8263128514,28515,28516,28517,28518,28519,28520,28521,28522,28523,28524,28525,
8263228526,28527,28528,28529,28530,28531,28532,28533,28534,28535,28536,28537,
8263328538,28539,28540,28541,28542,28543,28544,28545,28546,28547,28548,28549,
8263428550,28551,28552,28553,28554,28555,28556,28557,28558,28559,28560,28561,
8263528562,28563,28564,28565,28566,28567,28568,28569,28570,28571,28572,28573,
8263628574,28575,28576,28577,28578,28579,28580,28581,28582,28583,28584,28585,
8263728586,28587,28588,28589,28590,28591,28592,28593,28594,28595,28596,28597,
8263828598,28599,28600,28601,28602,28603,28604,28605,28606,28607,28608,28609,
8263928610,28611,28612,28613,28614,28615,28616,28617,28618,28619,28620,28621,
8264028622,28623,28624,28625,28626,28627,28628,28629,28630,28631,28632,28633,
8264128634,28635,28636,28637,28638,28639,28640,28641,28642,28643,28644,28645,
8264228646,28647,28648,28649,28650,28651,28652,28653,28654,28655,28656,28657,
8264328658,28659,28660,28661,28662,28663,28664,28665,28666,28667,28668,28669,
8264428670,28671,28672,28673,28674,28675,28676,28677,28678,28679,28680,28681,
8264528682,28683,28684,28685,28686,28687,28688,28689,28690,28691,28692,28693,
8264628694,28695,28696,28697,28698,28699,28700,28701,28702,28703,28704,28705,
8264728706,28707,28708,28709,28710,28711,28712,28713,28714,28715,28716,28717,
8264828718,28719,28720,28721,28722,28723,28724,28725,28726,28727,28728,28729,
8264928730,28731,28732,28733,28734,28735,28736,28737,28738,28739,28740,28741,
8265028742,28743,28744,28745,28746,28747,28748,28749,28750,28751,28752,28753,
8265128754,28755,28756,28757,28758,28759,28760,28761,28762,28763,28764,28765,
8265228766,28767,28768,28769,28770,28771,28772,28773,28774,28775,28776,28777,
8265328778,28779,28780,28781,28782,28783,28784,28785,28786,28787,28788,28789,
8265428790,28791,28792,28793,28794,28795,28796,28797,28798,28799,28800,28801,
8265528802,28803,28804,28805,28806,28807,28808,28809,28810,28811,28812,28813,
8265628814,28815,28816,28817,28818,28819,28820,28821,28822,28823,28824,28825,
8265728826,28827,28828,28829,28830,28831,28832,28833,28834,28835,28836,28837,
8265828838,28839,28840,28841,28842,28843,28844,28845,28846,28847,28848,28849,
8265928850,28851,28852,28853,28854,28855,28856,28857,28858,28859,28860,28861,
8266028862,28863,28864,28865,28866,28867,28868,28869,28870,28871,28872,28873,
8266128874,28875,28876,28877,28878,28879,28880,28881,28882,28883,28884,28885,
8266228886,28887,28888,28889,28890,28891,28892,28893,28894,28895,28896,28897,
8266328898,28899,28900,28901,28902,28903,28904,28905,28906,28907,28908,28909,
8266428910,28911,28912,28913,28914,28915,28916,28917,28918,28919,28920,28921,
8266528922,28923,28924,28925,28926,28927,28928,28929,28930,28931,28932,28933,
8266628934,28935,28936,28937,28938,28939,28940,28941,28942,28943,28944,28945,
8266728946,28947,28948,28949,28950,28951,28952,28953,28954,28955,28956,28957,
8266828958,28959,28960,28961,28962,28963,28964,28965,28966,28967,28968,28969,
8266928970,28971,28972,28973,28974,28975,28976,28977,28978,28979,28980,28981,
8267028982,28983,28984,28985,28986,28987,28988,28989,28990,28991,28992,28993,
8267128994,28995,28996,28997,28998,28999,29000,29001,29002,29003,29004,29005,
8267229006,29007,29008,29009,29010,29011,29012,29013,29014,29015,29016,29017,
8267329018,29019,29020,29021,29022,29023,29024,29025,29026,29027,29028,29029,
8267429030,29031,29032,29033,29034,29035,29036,29037,29038,29039,29040,29041,
8267529042,29043,29044,29045,29046,29047,29048,29049,29050,29051,29052,29053,
8267629054,29055,29056,29057,29058,29059,29060,29061,29062,29063,29064,29065,
8267729066,29067,29068,29069,29070,29071,29072,29073,29074,29075,29076,29077,
8267829078,29079,29080,29081,29082,29083,29084,29085,29086,29087,29088,29089,
8267929090,29091,29092,29093,29094,29095,29096,29097,29098,29099,29100,29101,
8268029102,29103,29104,29105,29106,29107,29108,29109,29110,29111,29112,29113,
8268129114,29115,29116,29117,29118,29119,29120,29121,29122,29123,29124,29125,
8268229126,29127,29128,29129,29130,29131,29132,29133,29134,29135,29136,29137,
8268329138,29139,29140,29141,29142,29143,29144,29145,29146,29147,29148,29149,
8268429150,29151,29152,29153,29154,29155,29156,29157,29158,29159,29160,29161,
8268529162,29163,29164,29165,29166,29167,29168,29169,29170,29171,29172,29173,
8268629174,29175,29176,29177,29178,29179,29180,29181,29182,29183,29184,29185,
8268729186,29187,29188,29189,29190,29191,29192,29193,29194,29195,29196,29197,
8268829198,29199,29200,29201,29202,29203,29204,29205,29206,29207,29208,29209,
8268929210,29211,29212,29213,29214,29215,29216,29217,29218,29219,29220,29221,
8269029222,29223,29224,29225,29226,29227,29228,29229,29230,29231,29232,29233,
8269129234,29235,29236,29237,29238,29239,29240,29241,29242,29243,29244,29245,
8269229246,29247,29248,29249,29250,29251,29252,29253,29254,29255,29256,29257,
8269329258,29259,29260,29261,29262,29263,29264,29265,29266,29267,29268,29269,
8269429270,29271,29272,29273,29274,29275,29276,29277,29278,29279,29280,29281,
8269529282,29283,29284,29285,29286,29287,29288,29289,29290,29291,29292,29293,
8269629294,29295,29296,29297,29298,29299,29300,29301,29302,29303,29304,29305,
8269729306,29307,29308,29309,29310,29311,29312,29313,29314,29315,29316,29317,
8269829318,29319,29320,29321,29322,29323,29324,29325,29326,29327,29328,29329,
8269929330,29331,29332,29333,29334,29335,29336,29337,29338,29339,29340,29341,
8270029342,29343,29344,29345,29346,29347,29348,29349,29350,29351,29352,29353,
8270129354,29355,29356,29357,29358,29359,29360,29361,29362,29363,29364,29365,
8270229366,29367,29368,29369,29370,29371,29372,29373,29374,29375,29376,29377,
8270329378,29379,29380,29381,29382,29383,29384,29385,29386,29387,29388,29389,
8270429390,29391,29392,29393,29394,29395,29396,29397,29398,29399,29400,29401,
8270529402,29403,29404,29405,29406,29407,29408,29409,29410,29411,29412,29413,
8270629414,29415,29416,29417,29418,29419,29420,29421,29422,29423,29424,29425,
8270729426,29427,29428,29429,29430,29431,29432,29433,29434,29435,29436,29437,
8270829438,29439,29440,29441,29442,29443,29444,29445,29446,29447,29448,29449,
8270929450,29451,29452,29453,29454,29455,29456,29457,29458,29459,29460,29461,
8271029462,29463,29464,29465,29466,29467,29468,29469,29470,29471,29472,29473,
8271129474,29475,29476,29477,29478,29479,29480,29481,29482,29483,29484,29485,
8271229486,29487,29488,29489,29490,29491,29492,29493,29494,29495,29496,29497,
8271329498,29499,29500,29501,29502,29503,29504,29505,29506,29507,29508,29509,
8271429510,29511,29512,29513,29514,29515,29516,29517,29518,29519,29520,29521,
8271529522,29523,29524,29525,29526,29527,29528,29529,29530,29531,29532,29533,
8271629534,29535,29536,29537,29538,29539,29540,29541,29542,29543,29544,29545,
8271729546,29547,29548,29549,29550,29551,29552,29553,29554,29555,29556,29557,
8271829558,29559,29560,29561,29562,29563,29564,29565,29566,29567,29568,29569,
8271929570,29571,29572,29573,29574,29575,29576,29577,29578,29579,29580,29581,
8272029582,29583,29584,29585,29586,29587,29588,29589,29590,29591,29592,29593,
8272129594,29595,29596,29597,29598,29599,29600,29601,29602,29603,29604,29605,
8272229606,29607,29608,29609,29610,29611,29612,29613,29614,29615,29616,29617,
8272329618,29619,29620,29621,29622,29623,29624,29625,29626,29627,29628,29629,
8272429630,29631,29632,29633,29634,29635,29636,29637,29638,29639,29640,29641,
8272529642,29643,29644,29645,29646,29647,29648,29649,29650,29651,29652,29653,
8272629654,29655,29656,29657,29658,29659,29660,29661,29662,29663,29664,29665,
8272729666,29667,29668,29669,29670,29671,29672,29673,29674,29675,29676,29677,
8272829678,29679,29680,29681,29682,29683,29684,29685,29686,29687,29688,29689,
8272929690,29691,29692,29693,29694,29695,29696,29697,29698,29699,29700,29701,
8273029702,29703,29704,29705,29706,29707,29708,29709,29710,29711,29712,29713,
8273129714,29715,29716,29717,29718,29719,29720,29721,29722,29723,29724,29725,
8273229726,29727,29728,29729,29730,29731,29732,29733,29734,29735,29736,29737,
8273329738,29739,29740,29741,29742,29743,29744,29745,29746,29747,29748,29749,
8273429750,29751,29752,29753,29754,29755,29756,29757,29758,29759,29760,29761,
8273529762,29763,29764,29765,29766,29767,29768,29769,29770,29771,29772,29773,
8273629774,29775,29776,29777,29778,29779,29780,29781,29782,29783,29784,29785,
8273729786,29787,29788,29789,29790,29791,29792,29793,29794,29795,29796,29797,
8273829798,29799,29800,29801,29802,29803,29804,29805,29806,29807,29808,29809,
8273929810,29811,29812,29813,29814,29815,29816,29817,29818,29819,29820,29821,
8274029822,29823,29824,29825,29826,29827,29828,29829,29830,29831,29832,29833,
8274129834,29835,29836,29837,29838,29839,29840,29841,29842,29843,29844,29845,
8274229846,29847,29848,29849,29850,29851,29852,29853,29854,29855,29856,29857,
8274329858,29859,29860,29861,29862,29863,29864,29865,29866,29867,29868,29869,
8274429870,29871,29872,29873,29874,29875,29876,29877,29878,29879,29880,29881,
8274529882,29883,29884,29885,29886,29887,29888,29889,29890,29891,29892,29893,
8274629894,29895,29896,29897,29898,29899,29900,29901,29902,29903,29904,29905,
8274729906,29907,29908,29909,29910,29911,29912,29913,29914,29915,29916,29917,
8274829918,29919,29920,29921,29922,29923,29924,29925,29926,29927,29928,29929,
8274929930,29931,29932,29933,29934,29935,29936,29937,29938,29939,29940,29941,
8275029942,29943,29944,29945,29946,29947,29948,29949,29950,29951,29952,29953,
8275129954,29955,29956,29957,29958,29959,29960,29961,29962,29963,29964,29965,
8275229966,29967,29968,29969,29970,29971,29972,29973,29974,29975,29976,29977,
8275329978,29979,29980,29981,29982,29983,29984,29985,29986,29987,29988,29989,
8275429990,29991,29992,29993,29994,29995,29996,29997,29998,29999,30000,30001,
8275530002,30003,30004,30005,30006,30007,30008,30009,30010,30011,30012,30013,
8275630014,30015,30016,30017,30018,30019,30020,30021,30022,30023,30024,30025,
8275730026,30027,30028,30029,30030,30031,30032,30033,30034,30035,30036,30037,
8275830038,30039,30040,30041,30042,30043,30044,30045,30046,30047,30048,30049,
8275930050,30051,30052,30053,30054,30055,30056,30057,30058,30059,30060,30061,
8276030062,30063,30064,30065,30066,30067,30068,30069,30070,30071,30072,30073,
8276130074,30075,30076,30077,30078,30079,30080,30081,30082,30083,30084,30085,
8276230086,30087,30088,30089,30090,30091,30092,30093,30094,30095,30096,30097,
8276330098,30099,30100,30101,30102,30103,30104,30105,30106,30107,30108,30109,
8276430110,30111,30112,30113,30114,30115,30116,30117,30118,30119,30120,30121,
8276530122,30123,30124,30125,30126,30127,30128,30129,30130,30131,30132,30133,
8276630134,30135,30136,30137,30138,30139,30140,30141,30142,30143,30144,30145,
8276730146,30147,30148,30149,30150,30151,30152,30153,30154,30155,30156,30157,
8276830158,30159,30160,30161,30162,30163,30164,30165,30166,30167,30168,30169,
8276930170,30171,30172,30173,30174,30175,30176,30177,30178,30179,30180,30181,
8277030182,30183,30184,30185,30186,30187,30188,30189,30190,30191,30192,30193,
8277130194,30195,30196,30197,30198,30199,30200,30201,30202,30203,30204,30205,
8277230206,30207,30208,30209,30210,30211,30212,30213,30214,30215,30216,30217,
8277330218,30219,30220,30221,30222,30223,30224,30225,30226,30227,30228,30229,
8277430230,30231,30232,30233,30234,30235,30236,30237,30238,30239,30240,30241,
8277530242,30243,30244,30245,30246,30247,30248,30249,30250,30251,30252,30253,
8277630254,30255,30256,30257,30258,30259,30260,30261,30262,30263,30264,30265,
8277730266,30267,30268,30269,30270,30271,30272,30273,30274,30275,30276,30277,
8277830278,30279,30280,30281,30282,30283,30284,30285,30286,30287,30288,30289,
8277930290,30291,30292,30293,30294,30295,30296,30297,30298,30299,30300,30301,
8278030302,30303,30304,30305,30306,30307,30308,30309,30310,30311,30312,30313,
8278130314,30315,30316,30317,30318,30319,30320,30321,30322,30323,30324,30325,
8278230326,30327,30328,30329,30330,30331,30332,30333,30334,30335,30336,30337,
8278330338,30339,30340,30341,30342,30343,30344,30345,30346,30347,30348,30349,
8278430350,30351,30352,30353,30354,30355,30356,30357,30358,30359,30360,30361,
8278530362,30363,30364,30365,30366,30367,30368,30369,30370,30371,30372,30373,
8278630374,30375,30376,30377,30378,30379,30380,30381,30382,30383,30384,30385,
8278730386,30387,30388,30389,30390,30391,30392,30393,30394,30395,30396,30397,
8278830398,30399,30400,30401,30402,30403,30404,30405,30406,30407,30408,30409,
8278930410,30411,30412,30413,30414,30415,30416,30417,30418,30419,30420,30421,
8279030422,30423,30424,30425,30426,30427,30428,30429,30430,30431,30432,30433,
8279130434,30435,30436,30437,30438,30439,30440,30441,30442,30443,30444,30445,
8279230446,30447,30448,30449,30450,30451,30452,30453,30454,30455,30456,30457,
8279330458,30459,30460,30461,30462,30463,30464,30465,30466,30467,30468,30469,
8279430470,30471,30472,30473,30474,30475,30476,30477,30478,30479,30480,30481,
8279530482,30483,30484,30485,30486,30487,30488,30489,30490,30491,30492,30493,
8279630494,30495,30496,30497,30498,30499,30500,30501,30502,30503,30504,30505,
8279730506,30507,30508,30509,30510,30511,30512,30513,30514,30515,30516,30517,
8279830518,30519,30520,30521,30522,30523,30524,30525,30526,30527,30528,30529,
8279930530,30531,30532,30533,30534,30535,30536,30537,30538,30539,30540,30541,
8280030542,30543,30544,30545,30546,30547,30548,30549,30550,30551,30552,30553,
8280130554,30555,30556,30557,30558,30559,30560,30561,30562,30563,30564,30565,
8280230566,30567,30568,30569,30570,30571,30572,30573,30574,30575,30576,30577,
8280330578,30579,30580,30581,30582,30583,30584,30585,30586,30587,30588,30589,
8280430590,30591,30592,30593,30594,30595,30596,30597,30598,30599,30600,30601,
8280530602,30603,30604,30605,30606,30607,30608,30609,30610,30611,30612,30613,
8280630614,30615,30616,30617,30618,30619,30620,30621,30622,30623,30624,30625,
8280730626,30627,30628,30629,30630,30631,30632,30633,30634,30635,30636,30637,
8280830638,30639,30640,30641,30642,30643,30644,30645,30646,30647,30648,30649,
8280930650,30651,30652,30653,30654,30655,30656,30657,30658,30659,30660,30661,
8281030662,30663,30664,30665,30666,30667,30668,30669,30670,30671,30672,30673,
8281130674,30675,30676,30677,30678,30679,30680,30681,30682,30683,30684,30685,
8281230686,30687,30688,30689,30690,30691,30692,30693,30694,30695,30696,30697,
8281330698,30699,30700,30701,30702,30703,30704,30705,30706,30707,30708,30709,
8281430710,30711,30712,30713,30714,30715,30716,30717,30718,30719,30720,30721,
8281530722,30723,30724,30725,30726,30727,30728,30729,30730,30731,30732,30733,
8281630734,30735,30736,30737,30738,30739,30740,30741,30742,30743,30744,30745,
8281730746,30747,30748,30749,30750,30751,30752,30753,30754,30755,30756,30757,
8281830758,30759,30760,30761,30762,30763,30764,30765,30766,30767,30768,30769,
8281930770,30771,30772,30773,30774,30775,30776,30777,30778,30779,30780,30781,
8282030782,30783,30784,30785,30786,30787,30788,30789,30790,30791,30792,30793,
8282130794,30795,30796,30797,30798,30799,30800,30801,30802,30803,30804,30805,
8282230806,30807,30808,30809,30810,30811,30812,30813,30814,30815,30816,30817,
8282330818,30819,30820,30821,30822,30823,30824,30825,30826,30827,30828,30829,
8282430830,30831,30832,30833,30834,30835,30836,30837,30838,30839,30840,30841,
8282530842,30843,30844,30845,30846,30847,30848,30849,30850,30851,30852,30853,
8282630854,30855,30856,30857,30858,30859,30860,30861,30862,30863,30864,30865,
8282730866,30867,30868,30869,30870,30871,30872,30873,30874,30875,30876,30877,
8282830878,30879,30880,30881,30882,30883,30884,30885,30886,30887,30888,30889,
8282930890,30891,30892,30893,30894,30895,30896,30897,30898,30899,30900,30901,
8283030902,30903,30904,30905,30906,30907,30908,30909,30910,30911,30912,30913,
8283130914,30915,30916,30917,30918,30919,30920,30921,30922,30923,30924,30925,
8283230926,30927,30928,30929,30930,30931,30932,30933,30934,30935,30936,30937,
8283330938,30939,30940,30941,30942,30943,30944,30945,30946,30947,30948,30949,
8283430950,30951,30952,30953,30954,30955,30956,30957,30958,30959,30960,30961,
8283530962,30963,30964,30965,30966,30967,30968,30969,30970,30971,30972,30973,
8283630974,30975,30976,30977,30978,30979,30980,30981,30982,30983,30984,30985,
8283730986,30987,30988,30989,30990,30991,30992,30993,30994,30995,30996,30997,
8283830998,30999,31000,31001,31002,31003,31004,31005,31006,31007,31008,31009,
8283931010,31011,31012,31013,31014,31015,31016,31017,31018,31019,31020,31021,
8284031022,31023,31024,31025,31026,31027,31028,31029,31030,31031,31032,31033,
8284131034,31035,31036,31037,31038,31039,31040,31041,31042,31043,31044,31045,
8284231046,31047,31048,31049,31050,31051,31052,31053,31054,31055,31056,31057,
8284331058,31059,31060,31061,31062,31063,31064,31065,31066,31067,31068,31069,
8284431070,31071,31072,31073,31074,31075,31076,31077,31078,31079,31080,31081,
8284531082,31083,31084,31085,31086,31087,31088,31089,31090,31091,31092,31093,
8284631094,31095,31096,31097,31098,31099,31100,31101,31102,31103,31104,31105,
8284731106,31107,31108,31109,31110,31111,31112,31113,31114,31115,31116,31117,
8284831118,31119,31120,31121,31122,31123,31124,31125,31126,31127,31128,31129,
8284931130,31131,31132,31133,31134,31135,31136,31137,31138,31139,31140,31141,
8285031142,31143,31144,31145,31146,31147,31148,31149,31150,31151,31152,31153,
8285131154,31155,31156,31157,31158,31159,31160,31161,31162,31163,31164,31165,
8285231166,31167,31168,31169,31170,31171,31172,31173,31174,31175,31176,31177,
8285331178,31179,31180,31181,31182,31183,31184,31185,31186,31187,31188,31189,
8285431190,31191,31192,31193,31194,31195,31196,31197,31198,31199,31200,31201,
8285531202,31203,31204,31205,31206,31207,31208,31209,31210,31211,31212,31213,
8285631214,31215,31216,31217,31218,31219,31220,31221,31222,31223,31224,31225,
8285731226,31227,31228,31229,31230,31231,31232,31233,31234,31235,31236,31237,
8285831238,31239,31240,31241,31242,31243,31244,31245,31246,31247,31248,31249,
8285931250,31251,31252,31253,31254,31255,31256,31257,31258,31259,31260,31261,
8286031262,31263,31264,31265,31266,31267,31268,31269,31270,31271,31272,31273,
8286131274,31275,31276,31277,31278,31279,31280,31281,31282,31283,31284,31285,
8286231286,31287,31288,31289,31290,31291,31292,31293,31294,31295,31296,31297,
8286331298,31299,31300,31301,31302,31303,31304,31305,31306,31307,31308,31309,
8286431310,31311,31312,31313,31314,31315,31316,31317,31318,31319,31320,31321,
8286531322,31323,31324,31325,31326,31327,31328,31329,31330,31331,31332,31333,
8286631334,31335,31336,31337,31338,31339,31340,31341,31342,31343,31344,31345,
8286731346,31347,31348,31349,31350,31351,31352,31353,31354,31355,31356,31357,
8286831358,31359,31360,31361,31362,31363,31364,31365,31366,31367,31368,31369,
8286931370,31371,31372,31373,31374,31375,31376,31377,31378,31379,31380,31381,
8287031382,31383,31384,31385,31386,31387,31388,31389,31390,31391,31392,31393,
8287131394,31395,31396,31397,31398,31399,31400,31401,31402,31403,31404,31405,
8287231406,31407,31408,31409,31410,31411,31412,31413,31414,31415,31416,31417,
8287331418,31419,31420,31421,31422,31423,31424,31425,31426,31427,31428,31429,
8287431430,31431,31432,31433,31434,31435,31436,31437,31438,31439,31440,31441,
8287531442,31443,31444,31445,31446,31447,31448,31449,31450,31451,31452,31453,
8287631454,31455,31456,31457,31458,31459,31460,31461,31462,31463,31464,31465,
8287731466,31467,31468,31469,31470,31471,31472,31473,31474,31475,31476,31477,
8287831478,31479,31480,31481,31482,31483,31484,31485,31486,31487,31488,31489,
8287931490,31491,31492,31493,31494,31495,31496,31497,31498,31499,31500,31501,
8288031502,31503,31504,31505,31506,31507,31508,31509,31510,31511,31512,31513,
8288131514,31515,31516,31517,31518,31519,31520,31521,31522,31523,31524,31525,
8288231526,31527,31528,31529,31530,31531,31532,31533,31534,31535,31536,31537,
8288331538,31539,31540,31541,31542,31543,31544,31545,31546,31547,31548,31549,
8288431550,31551,31552,31553,31554,31555,31556,31557,31558,31559,31560,31561,
8288531562,31563,31564,31565,31566,31567,31568,31569,31570,31571,31572,31573,
8288631574,31575,31576,31577,31578,31579,31580,31581,31582,31583,31584,31585,
8288731586,31587,31588,31589,31590,31591,31592,31593,31594,31595,31596,31597,
8288831598,31599,31600,31601,31602,31603,31604,31605,31606,31607,31608,31609,
8288931610,31611,31612,31613,31614,31615,31616,31617,31618,31619,31620,31621,
8289031622,31623,31624,31625,31626,31627,31628,31629,31630,31631,31632,31633,
8289131634,31635,31636,31637,31638,31639,31640,31641,31642,31643,31644,31645,
8289231646,31647,31648,31649,31650,31651,31652,31653,31654,31655,31656,31657,
8289331658,31659,31660,31661,31662,31663,31664,31665,31666,31667,31668,31669,
8289431670,31671,31672,31673,31674,31675,31676,31677,31678,31679,31680,31681,
8289531682,31683,31684,31685,31686,31687,31688,31689,31690,31691,31692,31693,
8289631694,31695,31696,31697,31698,31699,31700,31701,31702,31703,31704,31705,
8289731706,31707,31708,31709,31710,31711,31712,31713,31714,31715,31716,31717,
8289831718,31719,31720,31721,31722,31723,31724,31725,31726,31727,31728,31729,
8289931730,31731,31732,31733,31734,31735,31736,31737,31738,31739,31740,31741,
8290031742,31743,31744,31745,31746,31747,31748,31749,31750,31751,31752,31753,
8290131754,31755,31756,31757,31758,31759,31760,31761,31762,31763,31764,31765,
8290231766,31767,31768,31769,31770,31771,31772,31773,31774,31775,31776,31777,
8290331778,31779,31780,31781,31782,31783,31784,31785,31786,31787,31788,31789,
8290431790,31791,31792,31793,31794,31795,31796,31797,31798,31799,31800,31801,
8290531802,31803,31804,31805,31806,31807,31808,31809,31810,31811,31812,31813,
8290631814,31815,31816,31817,31818,31819,31820,31821,31822,31823,31824,31825,
8290731826,31827,31828,31829,31830,31831,31832,31833,31834,31835,31836,31837,
8290831838,31839,31840,31841,31842,31843,31844,31845,31846,31847,31848,31849,
8290931850,31851,31852,31853,31854,31855,31856,31857,31858,31859,31860,31861,
8291031862,31863,31864,31865,31866,31867,31868,31869,31870,31871,31872,31873,
8291131874,31875,31876,31877,31878,31879,31880,31881,31882,31883,31884,31885,
8291231886,31887,31888,31889,31890,31891,31892,31893,31894,31895,31896,31897,
8291331898,31899,31900,31901,31902,31903,31904,31905,31906,31907,31908,31909,
8291431910,31911,31912,31913,31914,31915,31916,31917,31918,31919,31920,31921,
8291531922,31923,31924,31925,31926,31927,31928,31929,31930,31931,31932,31933,
8291631934,31935,31936,31937,31938,31939,31940,31941,31942,31943,31944,31945,
8291731946,31947,31948,31949,31950,31951,31952,31953,31954,31955,31956,31957,
8291831958,31959,31960,31961,31962,31963,31964,31965,31966,31967,31968,31969,
8291931970,31971,31972,31973,31974,31975,31976,31977,31978,31979,31980,31981,
8292031982,31983,31984,31985,31986,31987,31988,31989,31990,31991,31992,31993,
8292131994,31995,31996,31997,31998,31999,32000,32001,32002,32003,32004,32005,
8292232006,32007,32008,32009,32010,32011,32012,32013,32014,32015,32016,32017,
8292332018,32019,32020,32021,32022,32023,32024,32025,32026,32027,32028,32029,
8292432030,32031,32032,32033,32034,32035,32036,32037,32038,32039,32040,32041,
8292532042,32043,32044,32045,32046,32047,32048,32049,32050,32051,32052,32053,
8292632054,32055,32056,32057,32058,32059,32060,32061,32062,32063,32064,32065,
8292732066,32067,32068,32069,32070,32071,32072,32073,32074,32075,32076,32077,
8292832078,32079,32080,32081,32082,32083,32084,32085,32086,32087,32088,32089,
8292932090,32091,32092,32093,32094,32095,32096,32097,32098,32099,32100,32101,
8293032102,32103,32104,32105,32106,32107,32108,32109,32110,32111,32112,32113,
8293132114,32115,32116,32117,32118,32119,32120,32121,32122,32123,32124,32125,
8293232126,32127,32128,32129,32130,32131,32132,32133,32134,32135,32136,32137,
8293332138,32139,32140,32141,32142,32143,32144,32145,32146,32147,32148,32149,
8293432150,32151,32152,32153,32154,32155,32156,32157,32158,32159,32160,32161,
8293532162,32163,32164,32165,32166,32167,32168,32169,32170,32171,32172,32173,
8293632174,32175,32176,32177,32178,32179,32180,32181,32182,32183,32184,32185,
8293732186,32187,32188,32189,32190,32191,32192,32193,32194,32195,32196,32197,
8293832198,32199,32200,32201,32202,32203,32204,32205,32206,32207,32208,32209,
8293932210,32211,32212,32213,32214,32215,32216,32217,32218,32219,32220,32221,
8294032222,32223,32224,32225,32226,32227,32228,32229,32230,32231,32232,32233,
8294132234,32235,32236,32237,32238,32239,32240,32241,32242,32243,32244,32245,
8294232246,32247,32248,32249,32250,32251,32252,32253,32254,32255,32256,32257,
8294332258,32259,32260,32261,32262,32263,32264,32265,32266,32267,32268,32269,
8294432270,32271,32272,32273,32274,32275,32276,32277,32278,32279,32280,32281,
8294532282,32283,32284,32285,32286,32287,32288,32289,32290,32291,32292,32293,
8294632294,32295,32296,32297,32298,32299,32300,32301,32302,32303,32304,32305,
8294732306,32307,32308,32309,32310,32311,32312,32313,32314,32315,32316,32317,
8294832318,32319,32320,32321,32322,32323,32324,32325,32326,32327,32328,32329,
8294932330,32331,32332,32333,32334,32335,32336,32337,32338,32339,32340,32341,
8295032342,32343,32344,32345,32346,32347,32348,32349,32350,32351,32352,32353,
8295132354,32355,32356,32357,32358,32359,32360,32361,32362,32363,32364,32365,
8295232366,32367,32368,32369,32370,32371,32372,32373,32374,32375,32376,32377,
8295332378,32379,32380,32381,32382,32383,32384,32385,32386,32387,32388,32389,
8295432390,32391,32392,32393,32394,32395,32396,32397,32398,32399,32400,32401,
8295532402,32403,32404,32405,32406,32407,32408,32409,32410,32411,32412,32413,
8295632414,32415,32416,32417,32418,32419,32420,32421,32422,32423,32424,32425,
8295732426,32427,32428,32429,32430,32431,32432,32433,32434,32435,32436,32437,
8295832438,32439,32440,32441,32442,32443,32444,32445,32446,32447,32448,32449,
8295932450,32451,32452,32453,32454,32455,32456,32457,32458,32459,32460,32461,
8296032462,32463,32464,32465,32466,32467,32468,32469,32470,32471,32472,32473,
8296132474,32475,32476,32477,32478,32479,32480,32481,32482,32483,32484,32485,
8296232486,32487,32488,32489,32490,32491,32492,32493,32494,32495,32496,32497,
8296332498,32499,32500,32501,32502,32503,32504,32505,32506,32507,32508,32509,
8296432510,32511,32512,32513,32514,32515,32516,32517,32518,32519,32520,32521,
8296532522,32523,32524,32525,32526,32527,32528,32529,32530,32531,32532,32533,
8296632534,32535,32536,32537,32538,32539,32540,32541,32542,32543,32544,32545,
8296732546,32547,32548,32549,32550,32551,32552,32553,32554,32555,32556,32557,
8296832558,32559,32560,32561,32562,32563,32564,32565,32566,32567,32568,32569,
8296932570,32571,32572,32573,32574,32575,32576,32577,32578,32579,32580,32581,
8297032582,32583,32584,32585,32586,32587,32588,32589,32590,32591,32592,32593,
8297132594,32595,32596,32597,32598,32599,32600,32601,32602,32603,32604,32605,
8297232606,32607,32608,32609,32610,32611,32612,32613,32614,32615,32616,32617,
8297332618,32619,32620,32621,32622,32623,32624,32625,32626,32627,32628,32629,
8297432630,32631,32632,32633,32634,32635,32636,32637,32638,32639,32640,32641,
8297532642,32643,32644,32645,32646,32647,32648,32649,32650,32651,32652,32653,
8297632654,32655,32656,32657,32658,32659,32660,32661,32662,32663,32664,32665,
8297732666,32667,32668,32669,32670,32671,32672,32673,32674,32675,32676,32677,
8297832678,32679,32680,32681,32682,32683,32684,32685,32686,32687,32688,32689,
8297932690,32691,32692,32693,32694,32695,32696,32697,32698,32699,32700,32701,
8298032702,32703,32704,32705,32706,32707,32708,32709,32710,32711,32712,32713,
8298132714,32715,32716,32717,32718,32719,32720,32721,32722,32723,32724,32725,
8298232726,32727,32728,32729,32730,32731,32732,32733,32734,32735,32736,32737,
8298332738,32739,32740,32741,32742,32743,32744,32745,32746,32747,32748,32749,
8298432750,32751,32752,32753,32754,32755,32756,32757,32758,32759,32760,32761,
8298532762,32763,32764,32765,32766,32767,32768L,32769L,32770L,32771L,32772L,
8298632773L,32774L,32775L,32776L,32777L,32778L,32779L,32780L,32781L,32782L,
8298732783L,32784L,32785L,32786L,32787L,32788L,32789L,32790L,32791L,32792L,
8298832793L,32794L,32795L,32796L,32797L,32798L,32799L,32800L,32801L,32802L,
8298932803L,32804L,32805L,32806L,32807L,32808L,32809L,32810L,32811L,32812L,
8299032813L,32814L,32815L,32816L,32817L,32818L,32819L,32820L,32821L,32822L,
8299132823L,32824L,32825L,32826L,32827L,32828L,32829L,32830L,32831L,32832L,
8299232833L,32834L,32835L,32836L,32837L,32838L,32839L,32840L,32841L,32842L,
8299332843L,32844L,32845L,32846L,32847L,32848L,32849L,32850L,32851L,32852L,
8299432853L,32854L,32855L,32856L,32857L,32858L,32859L,32860L,32861L,32862L,
8299532863L,32864L,32865L,32866L,32867L,32868L,32869L,32870L,32871L,32872L,
8299632873L,32874L,32875L,32876L,32877L,32878L,32879L,32880L,32881L,32882L,
8299732883L,32884L,32885L,32886L,32887L,32888L,32889L,32890L,32891L,32892L,
8299832893L,32894L,32895L,32896L,32897L,32898L,32899L,32900L,32901L,32902L,
8299932903L,32904L,32905L,32906L,32907L,32908L,32909L,32910L,32911L,32912L,
8300032913L,32914L,32915L,32916L,32917L,32918L,32919L,32920L,32921L,32922L,
8300132923L,32924L,32925L,32926L,32927L,32928L,32929L,32930L,32931L,32932L,
8300232933L,32934L,32935L,32936L,32937L,32938L,32939L,32940L,32941L,32942L,
8300332943L,32944L,32945L,32946L,32947L,32948L,32949L,32950L,32951L,32952L,
8300432953L,32954L,32955L,32956L,32957L,32958L,32959L,32960L,32961L,32962L,
8300532963L,32964L,32965L,32966L,32967L,32968L,32969L,32970L,32971L,32972L,
8300632973L,32974L,32975L,32976L,32977L,32978L,32979L,32980L,32981L,32982L,
8300732983L,32984L,32985L,32986L,32987L,32988L,32989L,32990L,32991L,32992L,
8300832993L,32994L,32995L,32996L,32997L,32998L,32999L,33000L,33001L,33002L,
8300933003L,33004L,33005L,33006L,33007L,33008L,33009L,33010L,33011L,33012L,
8301033013L,33014L,33015L,33016L,33017L,33018L,33019L,33020L,33021L,33022L,
8301133023L,33024L,33025L,33026L,33027L,33028L,33029L,33030L,33031L,33032L,
8301233033L,33034L,33035L,33036L,33037L,33038L,33039L,33040L,33041L,33042L,
8301333043L,33044L,33045L,33046L,33047L,33048L,33049L,33050L,33051L,33052L,
8301433053L,33054L,33055L,33056L,33057L,33058L,33059L,33060L,33061L,33062L,
8301533063L,33064L,33065L,33066L,33067L,33068L,33069L,33070L,33071L,33072L,
8301633073L,33074L,33075L,33076L,33077L,33078L,33079L,33080L,33081L,33082L,
8301733083L,33084L,33085L,33086L,33087L,33088L,33089L,33090L,33091L,33092L,
8301833093L,33094L,33095L,33096L,33097L,33098L,33099L,33100L,33101L,33102L,
8301933103L,33104L,33105L,33106L,33107L,33108L,33109L,33110L,33111L,33112L,
8302033113L,33114L,33115L,33116L,33117L,33118L,33119L,33120L,33121L,33122L,
8302133123L,33124L,33125L,33126L,33127L,33128L,33129L,33130L,33131L,33132L,
8302233133L,33134L,33135L,33136L,33137L,33138L,33139L,33140L,33141L,33142L,
8302333143L,33144L,33145L,33146L,33147L,33148L,33149L,33150L,33151L,33152L,
8302433153L,33154L,33155L,33156L,33157L,33158L,33159L,33160L,33161L,33162L,
8302533163L,33164L,33165L,33166L,33167L,33168L,33169L,33170L,33171L,33172L,
8302633173L,33174L,33175L,33176L,33177L,33178L,33179L,33180L,33181L,33182L,
8302733183L,33184L,33185L,33186L,33187L,33188L,33189L,33190L,33191L,33192L,
8302833193L,33194L,33195L,33196L,33197L,33198L,33199L,33200L,33201L,33202L,
8302933203L,33204L,33205L,33206L,33207L,33208L,33209L,33210L,33211L,33212L,
8303033213L,33214L,33215L,33216L,33217L,33218L,33219L,33220L,33221L,33222L,
8303133223L,33224L,33225L,33226L,33227L,33228L,33229L,33230L,33231L,33232L,
8303233233L,33234L,33235L,33236L,33237L,33238L,33239L,33240L,33241L,33242L,
8303333243L,33244L,33245L,33246L,33247L,33248L,33249L,33250L,33251L,33252L,
8303433253L,33254L,33255L,33256L,33257L,33258L,33259L,33260L,33261L,33262L,
8303533263L,33264L,33265L,33266L,33267L,33268L,33269L,33270L,33271L,33272L,
8303633273L,33274L,33275L,33276L,33277L,33278L,33279L,33280L,33281L,33282L,
8303733283L,33284L,33285L,33286L,33287L,33288L,33289L,33290L,33291L,33292L,
8303833293L,33294L,33295L,33296L,33297L,33298L,33299L,33300L,33301L,33302L,
8303933303L,33304L,33305L,33306L,33307L,33308L,33309L,33310L,33311L,33312L,
8304033313L,33314L,33315L,33316L,33317L,33318L,33319L,33320L,33321L,33322L,
8304133323L,33324L,33325L,33326L,33327L,33328L,33329L,33330L,33331L,33332L,
8304233333L,33334L,33335L,33336L,33337L,33338L,33339L,33340L,33341L,33342L,
8304333343L,33344L,33345L,33346L,33347L,33348L,33349L,33350L,33351L,33352L,
8304433353L,33354L,33355L,33356L,33357L,33358L,33359L,33360L,33361L,33362L,
8304533363L,33364L,33365L,33366L,33367L,33368L,33369L,33370L,33371L,33372L,
8304633373L,33374L,33375L,33376L,33377L,33378L,33379L,33380L,33381L,33382L,
8304733383L,33384L,33385L,33386L,33387L,33388L,33389L,33390L,33391L,33392L,
8304833393L,33394L,33395L,33396L,33397L,33398L,33399L,33400L,33401L,33402L,
8304933403L,33404L,33405L,33406L,33407L,33408L,33409L,33410L,33411L,33412L,
8305033413L,33414L,33415L,33416L,33417L,33418L,33419L,33420L,33421L,33422L,
8305133423L,33424L,33425L,33426L,33427L,33428L,33429L,33430L,33431L,33432L,
8305233433L,33434L,33435L,33436L,33437L,33438L,33439L,33440L,33441L,33442L,
8305333443L,33444L,33445L,33446L,33447L,33448L,33449L,33450L,33451L,33452L,
8305433453L,33454L,33455L,33456L,33457L,33458L,33459L,33460L,33461L,33462L,
8305533463L,33464L,33465L,33466L,33467L,33468L,33469L,33470L,33471L,33472L,
8305633473L,33474L,33475L,33476L,33477L,33478L,33479L,33480L,33481L,33482L,
8305733483L,33484L,33485L,33486L,33487L,33488L,33489L,33490L,33491L,33492L,
8305833493L,33494L,33495L,33496L,33497L,33498L,33499L,33500L,33501L,33502L,
8305933503L,33504L,33505L,33506L,33507L,33508L,33509L,33510L,33511L,33512L,
8306033513L,33514L,33515L,33516L,33517L,33518L,33519L,33520L,33521L,33522L,
8306133523L,33524L,33525L,33526L,33527L,33528L,33529L,33530L,33531L,33532L,
8306233533L,33534L,33535L,33536L,33537L,33538L,33539L,33540L,33541L,33542L,
8306333543L,33544L,33545L,33546L,33547L,33548L,33549L,33550L,33551L,33552L,
8306433553L,33554L,33555L,33556L,33557L,33558L,33559L,33560L,33561L,33562L,
8306533563L,33564L,33565L,33566L,33567L,33568L,33569L,33570L,33571L,33572L,
8306633573L,33574L,33575L,33576L,33577L,33578L,33579L,33580L,33581L,33582L,
8306733583L,33584L,33585L,33586L,33587L,33588L,33589L,33590L,33591L,33592L,
8306833593L,33594L,33595L,33596L,33597L,33598L,33599L,33600L,33601L,33602L,
8306933603L,33604L,33605L,33606L,33607L,33608L,33609L,33610L,33611L,33612L,
8307033613L,33614L,33615L,33616L,33617L,33618L,33619L,33620L,33621L,33622L,
8307133623L,33624L,33625L,33626L,33627L,33628L,33629L,33630L,33631L,33632L,
8307233633L,33634L,33635L,33636L,33637L,33638L,33639L,33640L,33641L,33642L,
8307333643L,33644L,33645L,33646L,33647L,33648L,33649L,33650L,33651L,33652L,
8307433653L,33654L,33655L,33656L,33657L,33658L,33659L,33660L,33661L,33662L,
8307533663L,33664L,33665L,33666L,33667L,33668L,33669L,33670L,33671L,33672L,
8307633673L,33674L,33675L,33676L,33677L,33678L,33679L,33680L,33681L,33682L,
8307733683L,33684L,33685L,33686L,33687L,33688L,33689L,33690L,33691L,33692L,
8307833693L,33694L,33695L,33696L,33697L,33698L,33699L,33700L,33701L,33702L,
8307933703L,33704L,33705L,33706L,33707L,33708L,33709L,33710L,33711L,33712L,
8308033713L,33714L,33715L,33716L,33717L,33718L,33719L,33720L,33721L,33722L,
8308133723L,33724L,33725L,33726L,33727L,33728L,33729L,33730L,33731L,33732L,
8308233733L,33734L,33735L,33736L,33737L,33738L,33739L,33740L,33741L,33742L,
8308333743L,33744L,33745L,33746L,33747L,33748L,33749L,33750L,33751L,33752L,
8308433753L,33754L,33755L,33756L,33757L,33758L,33759L,33760L,33761L,33762L,
8308533763L,33764L,33765L,33766L,33767L,33768L,33769L,33770L,33771L,33772L,
8308633773L,33774L,33775L,33776L,33777L,33778L,33779L,33780L,33781L,33782L,
8308733783L,33784L,33785L,33786L,33787L,33788L,33789L,33790L,33791L,33792L,
8308833793L,33794L,33795L,33796L,33797L,33798L,33799L,33800L,33801L,33802L,
8308933803L,33804L,33805L,33806L,33807L,33808L,33809L,33810L,33811L,33812L,
8309033813L,33814L,33815L,33816L,33817L,33818L,33819L,33820L,33821L,33822L,
8309133823L,33824L,33825L,33826L,33827L,33828L,33829L,33830L,33831L,33832L,
8309233833L,33834L,33835L,33836L,33837L,33838L,33839L,33840L,33841L,33842L,
8309333843L,33844L,33845L,33846L,33847L,33848L,33849L,33850L,33851L,33852L,
8309433853L,33854L,33855L,33856L,33857L,33858L,33859L,33860L,33861L,33862L,
8309533863L,33864L,33865L,33866L,33867L,33868L,33869L,33870L,33871L,33872L,
8309633873L,33874L,33875L,33876L,33877L,33878L,33879L,33880L,33881L,33882L,
8309733883L,33884L,33885L,33886L,33887L,33888L,33889L,33890L,33891L,33892L,
8309833893L,33894L,33895L,33896L,33897L,33898L,33899L,33900L,33901L,33902L,
8309933903L,33904L,33905L,33906L,33907L,33908L,33909L,33910L,33911L,33912L,
8310033913L,33914L,33915L,33916L,33917L,33918L,33919L,33920L,33921L,33922L,
8310133923L,33924L,33925L,33926L,33927L,33928L,33929L,33930L,33931L,33932L,
8310233933L,33934L,33935L,33936L,33937L,33938L,33939L,33940L,33941L,33942L,
8310333943L,33944L,33945L,33946L,33947L,33948L,33949L,33950L,33951L,33952L,
8310433953L,33954L,33955L,33956L,33957L,33958L,33959L,33960L,33961L,33962L,
8310533963L,33964L,33965L,33966L,33967L,33968L,33969L,33970L,33971L,33972L,
8310633973L,33974L,33975L,33976L,33977L,33978L,33979L,33980L,33981L,33982L,
8310733983L,33984L,33985L,33986L,33987L,33988L,33989L,33990L,33991L,33992L,
8310833993L,33994L,33995L,33996L,33997L,33998L,33999L,34000L,34001L,34002L,
8310934003L,34004L,34005L,34006L,34007L,34008L,34009L,34010L,34011L,34012L,
8311034013L,34014L,34015L,34016L,34017L,34018L,34019L,34020L,34021L,34022L,
8311134023L,34024L,34025L,34026L,34027L,34028L,34029L,34030L,34031L,34032L,
8311234033L,34034L,34035L,34036L,34037L,34038L,34039L,34040L,34041L,34042L,
8311334043L,34044L,34045L,34046L,34047L,34048L,34049L,34050L,34051L,34052L,
8311434053L,34054L,34055L,34056L,34057L,34058L,34059L,34060L,34061L,34062L,
8311534063L,34064L,34065L,34066L,34067L,34068L,34069L,34070L,34071L,34072L,
8311634073L,34074L,34075L,34076L,34077L,34078L,34079L,34080L,34081L,34082L,
8311734083L,34084L,34085L,34086L,34087L,34088L,34089L,34090L,34091L,34092L,
8311834093L,34094L,34095L,34096L,34097L,34098L,34099L,34100L,34101L,34102L,
8311934103L,34104L,34105L,34106L,34107L,34108L,34109L,34110L,34111L,34112L,
8312034113L,34114L,34115L,34116L,34117L,34118L,34119L,34120L,34121L,34122L,
8312134123L,34124L,34125L,34126L,34127L,34128L,34129L,34130L,34131L,34132L,
8312234133L,34134L,34135L,34136L,34137L,34138L,34139L,34140L,34141L,34142L,
8312334143L,34144L,34145L,34146L,34147L,34148L,34149L,34150L,34151L,34152L,
8312434153L,34154L,34155L,34156L,34157L,34158L,34159L,34160L,34161L,34162L,
8312534163L,34164L,34165L,34166L,34167L,34168L,34169L,34170L,34171L,34172L,
8312634173L,34174L,34175L,34176L,34177L,34178L,34179L,34180L,34181L,34182L,
8312734183L,34184L,34185L,34186L,34187L,34188L,34189L,34190L,34191L,34192L,
8312834193L,34194L,34195L,34196L,34197L,34198L,34199L,34200L,34201L,34202L,
8312934203L,34204L,34205L,34206L,34207L,34208L,34209L,34210L,34211L,34212L,
8313034213L,34214L,34215L,34216L,34217L,34218L,34219L,34220L,34221L,34222L,
8313134223L,34224L,34225L,34226L,34227L,34228L,34229L,34230L,34231L,34232L,
8313234233L,34234L,34235L,34236L,34237L,34238L,34239L,34240L,34241L,34242L,
8313334243L,34244L,34245L,34246L,34247L,34248L,34249L,34250L,34251L,34252L,
8313434253L,34254L,34255L,34256L,34257L,34258L,34259L,34260L,34261L,34262L,
8313534263L,34264L,34265L,34266L,34267L,34268L,34269L,34270L,34271L,34272L,
8313634273L,34274L,34275L,34276L,34277L,34278L,34279L,34280L,34281L,34282L,
8313734283L,34284L,34285L,34286L,34287L,34288L,34289L,34290L,34291L,34292L,
8313834293L,34294L,34295L,34296L,34297L,34298L,34299L,34300L,34301L,34302L,
8313934303L,34304L,34305L,34306L,34307L,34308L,34309L,34310L,34311L,34312L,
8314034313L,34314L,34315L,34316L,34317L,34318L,34319L,34320L,34321L,34322L,
8314134323L,34324L,34325L,34326L,34327L,34328L,34329L,34330L,34331L,34332L,
8314234333L,34334L,34335L,34336L,34337L,34338L,34339L,34340L,34341L,34342L,
8314334343L,34344L,34345L,34346L,34347L,34348L,34349L,34350L,34351L,34352L,
8314434353L,34354L,34355L,34356L,34357L,34358L,34359L,34360L,34361L,34362L,
8314534363L,34364L,34365L,34366L,34367L,34368L,34369L,34370L,34371L,34372L,
8314634373L,34374L,34375L,34376L,34377L,34378L,34379L,34380L,34381L,34382L,
8314734383L,34384L,34385L,34386L,34387L,34388L,34389L,34390L,34391L,34392L,
8314834393L,34394L,34395L,34396L,34397L,34398L,34399L,34400L,34401L,34402L,
8314934403L,34404L,34405L,34406L,34407L,34408L,34409L,34410L,34411L,34412L,
8315034413L,34414L,34415L,34416L,34417L,34418L,34419L,34420L,34421L,34422L,
8315134423L,34424L,34425L,34426L,34427L,34428L,34429L,34430L,34431L,34432L,
8315234433L,34434L,34435L,34436L,34437L,34438L,34439L,34440L,34441L,34442L,
8315334443L,34444L,34445L,34446L,34447L,34448L,34449L,34450L,34451L,34452L,
8315434453L,34454L,34455L,34456L,34457L,34458L,34459L,34460L,34461L,34462L,
8315534463L,34464L,34465L,34466L,34467L,34468L,34469L,34470L,34471L,34472L,
8315634473L,34474L,34475L,34476L,34477L,34478L,34479L,34480L,34481L,34482L,
8315734483L,34484L,34485L,34486L,34487L,34488L,34489L,34490L,34491L,34492L,
8315834493L,34494L,34495L,34496L,34497L,34498L,34499L,34500L,34501L,34502L,
8315934503L,34504L,34505L,34506L,34507L,34508L,34509L,34510L,34511L,34512L,
8316034513L,34514L,34515L,34516L,34517L,34518L,34519L,34520L,34521L,34522L,
8316134523L,34524L,34525L,34526L,34527L,34528L,34529L,34530L,34531L,34532L,
8316234533L,34534L,34535L,34536L,34537L,34538L,34539L,34540L,34541L,34542L,
8316334543L,34544L,34545L,34546L,34547L,34548L,34549L,34550L,34551L,34552L,
8316434553L,34554L,34555L,34556L,34557L,34558L,34559L,34560L,34561L,34562L,
8316534563L,34564L,34565L,34566L,34567L,34568L,34569L,34570L,34571L,34572L,
8316634573L,34574L,34575L,34576L,34577L,34578L,34579L,34580L,34581L,34582L,
8316734583L,34584L,34585L,34586L,34587L,34588L,34589L,34590L,34591L,34592L,
8316834593L,34594L,34595L,34596L,34597L,34598L,34599L,34600L,34601L,34602L,
8316934603L,34604L,34605L,34606L,34607L,34608L,34609L,34610L,34611L,34612L,
8317034613L,34614L,34615L,34616L,34617L,34618L,34619L,34620L,34621L,34622L,
8317134623L,34624L,34625L,34626L,34627L,34628L,34629L,34630L,34631L,34632L,
8317234633L,34634L,34635L,34636L,34637L,34638L,34639L,34640L,34641L,34642L,
8317334643L,34644L,34645L,34646L,34647L,34648L,34649L,34650L,34651L,34652L,
8317434653L,34654L,34655L,34656L,34657L,34658L,34659L,34660L,34661L,34662L,
8317534663L,34664L,34665L,34666L,34667L,34668L,34669L,34670L,34671L,34672L,
8317634673L,34674L,34675L,34676L,34677L,34678L,34679L,34680L,34681L,34682L,
8317734683L,34684L,34685L,34686L,34687L,34688L,34689L,34690L,34691L,34692L,
8317834693L,34694L,34695L,34696L,34697L,34698L,34699L,34700L,34701L,34702L,
8317934703L,34704L,34705L,34706L,34707L,34708L,34709L,34710L,34711L,34712L,
8318034713L,34714L,34715L,34716L,34717L,34718L,34719L,34720L,34721L,34722L,
8318134723L,34724L,34725L,34726L,34727L,34728L,34729L,34730L,34731L,34732L,
8318234733L,34734L,34735L,34736L,34737L,34738L,34739L,34740L,34741L,34742L,
8318334743L,34744L,34745L,34746L,34747L,34748L,34749L,34750L,34751L,34752L,
8318434753L,34754L,34755L,34756L,34757L,34758L,34759L,34760L,34761L,34762L,
8318534763L,34764L,34765L,34766L,34767L,34768L,34769L,34770L,34771L,34772L,
8318634773L,34774L,34775L,34776L,34777L,34778L,34779L,34780L,34781L,34782L,
8318734783L,34784L,34785L,34786L,34787L,34788L,34789L,34790L,34791L,34792L,
8318834793L,34794L,34795L,34796L,34797L,34798L,34799L,34800L,34801L,34802L,
8318934803L,34804L,34805L,34806L,34807L,34808L,34809L,34810L,34811L,34812L,
8319034813L,34814L,34815L,34816L,34817L,34818L,34819L,34820L,34821L,34822L,
8319134823L,34824L,34825L,34826L,34827L,34828L,34829L,34830L,34831L,34832L,
8319234833L,34834L,34835L,34836L,34837L,34838L,34839L,34840L,34841L,34842L,
8319334843L,34844L,34845L,34846L,34847L,34848L,34849L,34850L,34851L,34852L,
8319434853L,34854L,34855L,34856L,34857L,34858L,34859L,34860L,34861L,34862L,
8319534863L,34864L,34865L,34866L,34867L,34868L,34869L,34870L,34871L,34872L,
8319634873L,34874L,34875L,34876L,34877L,34878L,34879L,34880L,34881L,34882L,
8319734883L,34884L,34885L,34886L,34887L,34888L,34889L,34890L,34891L,34892L,
8319834893L,34894L,34895L,34896L,34897L,34898L,34899L,34900L,34901L,34902L,
8319934903L,34904L,34905L,34906L,34907L,34908L,34909L,34910L,34911L,34912L,
8320034913L,34914L,34915L,34916L,34917L,34918L,34919L,34920L,34921L,34922L,
8320134923L,34924L,34925L,34926L,34927L,34928L,34929L,34930L,34931L,34932L,
8320234933L,34934L,34935L,34936L,34937L,34938L,34939L,34940L,34941L,34942L,
8320334943L,34944L,34945L,34946L,34947L,34948L,34949L,34950L,34951L,34952L,
8320434953L,34954L,34955L,34956L,34957L,34958L,34959L,34960L,34961L,34962L,
8320534963L,34964L,34965L,34966L,34967L,34968L,34969L,34970L,34971L,34972L,
8320634973L,34974L,34975L,34976L,34977L,34978L,34979L,34980L,34981L,34982L,
8320734983L,34984L,34985L,34986L,34987L,34988L,34989L,34990L,34991L,34992L,
8320834993L,34994L,34995L,34996L,34997L,34998L,34999L,35000L,35001L,35002L,
8320935003L,35004L,35005L,35006L,35007L,35008L,35009L,35010L,35011L,35012L,
8321035013L,35014L,35015L,35016L,35017L,35018L,35019L,35020L,35021L,35022L,
8321135023L,35024L,35025L,35026L,35027L,35028L,35029L,35030L,35031L,35032L,
8321235033L,35034L,35035L,35036L,35037L,35038L,35039L,35040L,35041L,35042L,
8321335043L,35044L,35045L,35046L,35047L,35048L,35049L,35050L,35051L,35052L,
8321435053L,35054L,35055L,35056L,35057L,35058L,35059L,35060L,35061L,35062L,
8321535063L,35064L,35065L,35066L,35067L,35068L,35069L,35070L,35071L,35072L,
8321635073L,35074L,35075L,35076L,35077L,35078L,35079L,35080L,35081L,35082L,
8321735083L,35084L,35085L,35086L,35087L,35088L,35089L,35090L,35091L,35092L,
8321835093L,35094L,35095L,35096L,35097L,35098L,35099L,35100L,35101L,35102L,
8321935103L,35104L,35105L,35106L,35107L,35108L,35109L,35110L,35111L,35112L,
8322035113L,35114L,35115L,35116L,35117L,35118L,35119L,35120L,35121L,35122L,
8322135123L,35124L,35125L,35126L,35127L,35128L,35129L,35130L,35131L,35132L,
8322235133L,35134L,35135L,35136L,35137L,35138L,35139L,35140L,35141L,35142L,
8322335143L,35144L,35145L,35146L,35147L,35148L,35149L,35150L,35151L,35152L,
8322435153L,35154L,35155L,35156L,35157L,35158L,35159L,35160L,35161L,35162L,
8322535163L,35164L,35165L,35166L,35167L,35168L,35169L,35170L,35171L,35172L,
8322635173L,35174L,35175L,35176L,35177L,35178L,35179L,35180L,35181L,35182L,
8322735183L,35184L,35185L,35186L,35187L,35188L,35189L,35190L,35191L,35192L,
8322835193L,35194L,35195L,35196L,35197L,35198L,35199L,35200L,35201L,35202L,
8322935203L,35204L,35205L,35206L,35207L,35208L,35209L,35210L,35211L,35212L,
8323035213L,35214L,35215L,35216L,35217L,35218L,35219L,35220L,35221L,35222L,
8323135223L,35224L,35225L,35226L,35227L,35228L,35229L,35230L,35231L,35232L,
8323235233L,35234L,35235L,35236L,35237L,35238L,35239L,35240L,35241L,35242L,
8323335243L,35244L,35245L,35246L,35247L,35248L,35249L,35250L,35251L,35252L,
8323435253L,35254L,35255L,35256L,35257L,35258L,35259L,35260L,35261L,35262L,
8323535263L,35264L,35265L,35266L,35267L,35268L,35269L,35270L,35271L,35272L,
8323635273L,35274L,35275L,35276L,35277L,35278L,35279L,35280L,35281L,35282L,
8323735283L,35284L,35285L,35286L,35287L,35288L,35289L,35290L,35291L,35292L,
8323835293L,35294L,35295L,35296L,35297L,35298L,35299L,35300L,35301L,35302L,
8323935303L,35304L,35305L,35306L,35307L,35308L,35309L,35310L,35311L,35312L,
8324035313L,35314L,35315L,35316L,35317L,35318L,35319L,35320L,35321L,35322L,
8324135323L,35324L,35325L,35326L,35327L,35328L,35329L,35330L,35331L,35332L,
8324235333L,35334L,35335L,35336L,35337L,35338L,35339L,35340L,35341L,35342L,
8324335343L,35344L,35345L,35346L,35347L,35348L,35349L,35350L,35351L,35352L,
8324435353L,35354L,35355L,35356L,35357L,35358L,35359L,35360L,35361L,35362L,
8324535363L,35364L,35365L,35366L,35367L,35368L,35369L,35370L,35371L,35372L,
8324635373L,35374L,35375L,35376L,35377L,35378L,35379L,35380L,35381L,35382L,
8324735383L,35384L,35385L,35386L,35387L,35388L,35389L,35390L,35391L,35392L,
8324835393L,35394L,35395L,35396L,35397L,35398L,35399L,35400L,35401L,35402L,
8324935403L,35404L,35405L,35406L,35407L,35408L,35409L,35410L,35411L,35412L,
8325035413L,35414L,35415L,35416L,35417L,35418L,35419L,35420L,35421L,35422L,
8325135423L,35424L,35425L,35426L,35427L,35428L,35429L,35430L,35431L,35432L,
8325235433L,35434L,35435L,35436L,35437L,35438L,35439L,35440L,35441L,35442L,
8325335443L,35444L,35445L,35446L,35447L,35448L,35449L,35450L,35451L,35452L,
8325435453L,35454L,35455L,35456L,35457L,35458L,35459L,35460L,35461L,35462L,
8325535463L,35464L,35465L,35466L,35467L,35468L,35469L,35470L,35471L,35472L,
8325635473L,35474L,35475L,35476L,35477L,35478L,35479L,35480L,35481L,35482L,
8325735483L,35484L,35485L,35486L,35487L,35488L,35489L,35490L,35491L,35492L,
8325835493L,35494L,35495L,35496L,35497L,35498L,35499L,35500L,35501L,35502L,
8325935503L,35504L,35505L,35506L,35507L,35508L,35509L,35510L,35511L,35512L,
8326035513L,35514L,35515L,35516L,35517L,35518L,35519L,35520L,35521L,35522L,
8326135523L,35524L,35525L,35526L,35527L,35528L,35529L,35530L,35531L,35532L,
8326235533L,35534L,35535L,35536L,35537L,35538L,35539L,35540L,35541L,35542L,
8326335543L,35544L,35545L,35546L,35547L,35548L,35549L,35550L,35551L,35552L,
8326435553L,35554L,35555L,35556L,35557L,35558L,35559L,35560L,35561L,35562L,
8326535563L,35564L,35565L,35566L,35567L,35568L,35569L,35570L,35571L,35572L,
8326635573L,35574L,35575L,35576L,35577L,35578L,35579L,35580L,35581L,35582L,
8326735583L,35584L,35585L,35586L,35587L,35588L,35589L,35590L,35591L,35592L,
8326835593L,35594L,35595L,35596L,35597L,35598L,35599L,35600L,35601L,35602L,
8326935603L,35604L,35605L,35606L,35607L,35608L,35609L,35610L,35611L,35612L,
8327035613L,35614L,35615L,35616L,35617L,35618L,35619L,35620L,35621L,35622L,
8327135623L,35624L,35625L,35626L,35627L,35628L,35629L,35630L,35631L,35632L,
8327235633L,35634L,35635L,35636L,35637L,35638L,35639L,35640L,35641L,35642L,
8327335643L,35644L,35645L,35646L,35647L,35648L,35649L,35650L,35651L,35652L,
8327435653L,35654L,35655L,35656L,35657L,35658L,35659L,35660L,35661L,35662L,
8327535663L,35664L,35665L,35666L,35667L,35668L,35669L,35670L,35671L,35672L,
8327635673L,35674L,35675L,35676L,35677L,35678L,35679L,35680L,35681L,35682L,
8327735683L,35684L,35685L,35686L,35687L,35688L,35689L,35690L,35691L,35692L,
8327835693L,35694L,35695L,35696L,35697L,35698L,35699L,35700L,35701L,35702L,
8327935703L,35704L,35705L,35706L,35707L,35708L,35709L,35710L,35711L,35712L,
8328035713L,35714L,35715L,35716L,35717L,35718L,35719L,35720L,35721L,35722L,
8328135723L,35724L,35725L,35726L,35727L,35728L,35729L,35730L,35731L,35732L,
8328235733L,35734L,35735L,35736L,35737L,35738L,35739L,35740L,35741L,35742L,
8328335743L,35744L,35745L,35746L,35747L,35748L,35749L,35750L,35751L,35752L,
8328435753L,35754L,35755L,35756L,35757L,35758L,35759L,35760L,35761L,35762L,
8328535763L,35764L,35765L,35766L,35767L,35768L,35769L,35770L,35771L,35772L,
8328635773L,35774L,35775L,35776L,35777L,35778L,35779L,35780L,35781L,35782L,
8328735783L,35784L,35785L,35786L,35787L,35788L,35789L,35790L,35791L,35792L,
8328835793L,35794L,35795L,35796L,35797L,35798L,35799L,35800L,35801L,35802L,
8328935803L,35804L,35805L,35806L,35807L,35808L,35809L,35810L,35811L,35812L,
8329035813L,35814L,35815L,35816L,35817L,35818L,35819L,35820L,35821L,35822L,
8329135823L,35824L,35825L,35826L,35827L,35828L,35829L,35830L,35831L,35832L,
8329235833L,35834L,35835L,35836L,35837L,35838L,35839L,35840L,35841L,35842L,
8329335843L,35844L,35845L,35846L,35847L,35848L,35849L,35850L,35851L,35852L,
8329435853L,35854L,35855L,35856L,35857L,35858L,35859L,35860L,35861L,35862L,
8329535863L,35864L,35865L,35866L,35867L,35868L,35869L,35870L,35871L,35872L,
8329635873L,35874L,35875L,35876L,35877L,35878L,35879L,35880L,35881L,35882L,
8329735883L,35884L,35885L,35886L,35887L,35888L,35889L,35890L,35891L,35892L,
8329835893L,35894L,35895L,35896L,35897L,35898L,35899L,35900L,35901L,35902L,
8329935903L,35904L,35905L,35906L,35907L,35908L,35909L,35910L,35911L,35912L,
8330035913L,35914L,35915L,35916L,35917L,35918L,35919L,35920L,35921L,35922L,
8330135923L,35924L,35925L,35926L,35927L,35928L,35929L,35930L,35931L,35932L,
8330235933L,35934L,35935L,35936L,35937L,35938L,35939L,35940L,35941L,35942L,
8330335943L,35944L,35945L,35946L,35947L,35948L,35949L,35950L,35951L,35952L,
8330435953L,35954L,35955L,35956L,35957L,35958L,35959L,35960L,35961L,35962L,
8330535963L,35964L,35965L,35966L,35967L,35968L,35969L,35970L,35971L,35972L,
8330635973L,35974L,35975L,35976L,35977L,35978L,35979L,35980L,35981L,35982L,
8330735983L,35984L,35985L,35986L,35987L,35988L,35989L,35990L,35991L,35992L,
8330835993L,35994L,35995L,35996L,35997L,35998L,35999L,36000L,36001L,36002L,
8330936003L,36004L,36005L,36006L,36007L,36008L,36009L,36010L,36011L,36012L,
8331036013L,36014L,36015L,36016L,36017L,36018L,36019L,36020L,36021L,36022L,
8331136023L,36024L,36025L,36026L,36027L,36028L,36029L,36030L,36031L,36032L,
8331236033L,36034L,36035L,36036L,36037L,36038L,36039L,36040L,36041L,36042L,
8331336043L,36044L,36045L,36046L,36047L,36048L,36049L,36050L,36051L,36052L,
8331436053L,36054L,36055L,36056L,36057L,36058L,36059L,36060L,36061L,36062L,
8331536063L,36064L,36065L,36066L,36067L,36068L,36069L,36070L,36071L,36072L,
8331636073L,36074L,36075L,36076L,36077L,36078L,36079L,36080L,36081L,36082L,
8331736083L,36084L,36085L,36086L,36087L,36088L,36089L,36090L,36091L,36092L,
8331836093L,36094L,36095L,36096L,36097L,36098L,36099L,36100L,36101L,36102L,
8331936103L,36104L,36105L,36106L,36107L,36108L,36109L,36110L,36111L,36112L,
8332036113L,36114L,36115L,36116L,36117L,36118L,36119L,36120L,36121L,36122L,
8332136123L,36124L,36125L,36126L,36127L,36128L,36129L,36130L,36131L,36132L,
8332236133L,36134L,36135L,36136L,36137L,36138L,36139L,36140L,36141L,36142L,
8332336143L,36144L,36145L,36146L,36147L,36148L,36149L,36150L,36151L,36152L,
8332436153L,36154L,36155L,36156L,36157L,36158L,36159L,36160L,36161L,36162L,
8332536163L,36164L,36165L,36166L,36167L,36168L,36169L,36170L,36171L,36172L,
8332636173L,36174L,36175L,36176L,36177L,36178L,36179L,36180L,36181L,36182L,
8332736183L,36184L,36185L,36186L,36187L,36188L,36189L,36190L,36191L,36192L,
8332836193L,36194L,36195L,36196L,36197L,36198L,36199L,36200L,36201L,36202L,
8332936203L,36204L,36205L,36206L,36207L,36208L,36209L,36210L,36211L,36212L,
8333036213L,36214L,36215L,36216L,36217L,36218L,36219L,36220L,36221L,36222L,
8333136223L,36224L,36225L,36226L,36227L,36228L,36229L,36230L,36231L,36232L,
8333236233L,36234L,36235L,36236L,36237L,36238L,36239L,36240L,36241L,36242L,
8333336243L,36244L,36245L,36246L,36247L,36248L,36249L,36250L,36251L,36252L,
8333436253L,36254L,36255L,36256L,36257L,36258L,36259L,36260L,36261L,36262L,
8333536263L,36264L,36265L,36266L,36267L,36268L,36269L,36270L,36271L,36272L,
8333636273L,36274L,36275L,36276L,36277L,36278L,36279L,36280L,36281L,36282L,
8333736283L,36284L,36285L,36286L,36287L,36288L,36289L,36290L,36291L,36292L,
8333836293L,36294L,36295L,36296L,36297L,36298L,36299L,36300L,36301L,36302L,
8333936303L,36304L,36305L,36306L,36307L,36308L,36309L,36310L,36311L,36312L,
8334036313L,36314L,36315L,36316L,36317L,36318L,36319L,36320L,36321L,36322L,
8334136323L,36324L,36325L,36326L,36327L,36328L,36329L,36330L,36331L,36332L,
8334236333L,36334L,36335L,36336L,36337L,36338L,36339L,36340L,36341L,36342L,
8334336343L,36344L,36345L,36346L,36347L,36348L,36349L,36350L,36351L,36352L,
8334436353L,36354L,36355L,36356L,36357L,36358L,36359L,36360L,36361L,36362L,
8334536363L,36364L,36365L,36366L,36367L,36368L,36369L,36370L,36371L,36372L,
8334636373L,36374L,36375L,36376L,36377L,36378L,36379L,36380L,36381L,36382L,
8334736383L,36384L,36385L,36386L,36387L,36388L,36389L,36390L,36391L,36392L,
8334836393L,36394L,36395L,36396L,36397L,36398L,36399L,36400L,36401L,36402L,
8334936403L,36404L,36405L,36406L,36407L,36408L,36409L,36410L,36411L,36412L,
8335036413L,36414L,36415L,36416L,36417L,36418L,36419L,36420L,36421L,36422L,
8335136423L,36424L,36425L,36426L,36427L,36428L,36429L,36430L,36431L,36432L,
8335236433L,36434L,36435L,36436L,36437L,36438L,36439L,36440L,36441L,36442L,
8335336443L,36444L,36445L,36446L,36447L,36448L,36449L,36450L,36451L,36452L,
8335436453L,36454L,36455L,36456L,36457L,36458L,36459L,36460L,36461L,36462L,
8335536463L,36464L,36465L,36466L,36467L,36468L,36469L,36470L,36471L,36472L,
8335636473L,36474L,36475L,36476L,36477L,36478L,36479L,36480L,36481L,36482L,
8335736483L,36484L,36485L,36486L,36487L,36488L,36489L,36490L,36491L,36492L,
8335836493L,36494L,36495L,36496L,36497L,36498L,36499L,36500L,36501L,36502L,
8335936503L,36504L,36505L,36506L,36507L,36508L,36509L,36510L,36511L,36512L,
8336036513L,36514L,36515L,36516L,36517L,36518L,36519L,36520L,36521L,36522L,
8336136523L,36524L,36525L,36526L,36527L,36528L,36529L,36530L,36531L,36532L,
8336236533L,36534L,36535L,36536L,36537L,36538L,36539L,36540L,36541L,36542L,
8336336543L,36544L,36545L,36546L,36547L,36548L,36549L,36550L,36551L,36552L,
8336436553L,36554L,36555L,36556L,36557L,36558L,36559L,36560L,36561L,36562L,
8336536563L,36564L,36565L,36566L,36567L,36568L,36569L,36570L,36571L,36572L,
8336636573L,36574L,36575L,36576L,36577L,36578L,36579L,36580L,36581L,36582L,
8336736583L,36584L,36585L,36586L,36587L,36588L,36589L,36590L,36591L,36592L,
8336836593L,36594L,36595L,36596L,36597L,36598L,36599L,36600L,36601L,36602L,
8336936603L,36604L,36605L,36606L,36607L,36608L,36609L,36610L,36611L,36612L,
8337036613L,36614L,36615L,36616L,36617L,36618L,36619L,36620L,36621L,36622L,
8337136623L,36624L,36625L,36626L,36627L,36628L,36629L,36630L,36631L,36632L,
8337236633L,36634L,36635L,36636L,36637L,36638L,36639L,36640L,36641L,36642L,
8337336643L,36644L,36645L,36646L,36647L,36648L,36649L,36650L,36651L,36652L,
8337436653L,36654L,36655L,36656L,36657L,36658L,36659L,36660L,36661L,36662L,
8337536663L,36664L,36665L,36666L,36667L,36668L,36669L,36670L,36671L,36672L,
8337636673L,36674L,36675L,36676L,36677L,36678L,36679L,36680L,36681L,36682L,
8337736683L,36684L,36685L,36686L,36687L,36688L,36689L,36690L,36691L,36692L,
8337836693L,36694L,36695L,36696L,36697L,36698L,36699L,36700L,36701L,36702L,
8337936703L,36704L,36705L,36706L,36707L,36708L,36709L,36710L,36711L,36712L,
8338036713L,36714L,36715L,36716L,36717L,36718L,36719L,36720L,36721L,36722L,
8338136723L,36724L,36725L,36726L,36727L,36728L,36729L,36730L,36731L,36732L,
8338236733L,36734L,36735L,36736L,36737L,36738L,36739L,36740L,36741L,36742L,
8338336743L,36744L,36745L,36746L,36747L,36748L,36749L,36750L,36751L,36752L,
8338436753L,36754L,36755L,36756L,36757L,36758L,36759L,36760L,36761L,36762L,
8338536763L,36764L,36765L,36766L,36767L,36768L,36769L,36770L,36771L,36772L,
8338636773L,36774L,36775L,36776L,36777L,36778L,36779L,36780L,36781L,36782L,
8338736783L,36784L,36785L,36786L,36787L,36788L,36789L,36790L,36791L,36792L,
8338836793L,36794L,36795L,36796L,36797L,36798L,36799L,36800L,36801L,36802L,
8338936803L,36804L,36805L,36806L,36807L,36808L,36809L,36810L,36811L,36812L,
8339036813L,36814L,36815L,36816L,36817L,36818L,36819L,36820L,36821L,36822L,
8339136823L,36824L,36825L,36826L,36827L,36828L,36829L,36830L,36831L,36832L,
8339236833L,36834L,36835L,36836L,36837L,36838L,36839L,36840L,36841L,36842L,
8339336843L,36844L,36845L,36846L,36847L,36848L,36849L,36850L,36851L,36852L,
8339436853L,36854L,36855L,36856L,36857L,36858L,36859L,36860L,36861L,36862L,
8339536863L,36864L,36865L,36866L,36867L,36868L,36869L,36870L,36871L,36872L,
8339636873L,36874L,36875L,36876L,36877L,36878L,36879L,36880L,36881L,36882L,
8339736883L,36884L,36885L,36886L,36887L,36888L,36889L,36890L,36891L,36892L,
8339836893L,36894L,36895L,36896L,36897L,36898L,36899L,36900L,36901L,36902L,
8339936903L,36904L,36905L,36906L,36907L,36908L,36909L,36910L,36911L,36912L,
8340036913L,36914L,36915L,36916L,36917L,36918L,36919L,36920L,36921L,36922L,
8340136923L,36924L,36925L,36926L,36927L,36928L,36929L,36930L,36931L,36932L,
8340236933L,36934L,36935L,36936L,36937L,36938L,36939L,36940L,36941L,36942L,
8340336943L,36944L,36945L,36946L,36947L,36948L,36949L,36950L,36951L,36952L,
8340436953L,36954L,36955L,36956L,36957L,36958L,36959L,36960L,36961L,36962L,
8340536963L,36964L,36965L,36966L,36967L,36968L,36969L,36970L,36971L,36972L,
8340636973L,36974L,36975L,36976L,36977L,36978L,36979L,36980L,36981L,36982L,
8340736983L,36984L,36985L,36986L,36987L,36988L,36989L,36990L,36991L,36992L,
8340836993L,36994L,36995L,36996L,36997L,36998L,36999L,37000L,37001L,37002L,
8340937003L,37004L,37005L,37006L,37007L,37008L,37009L,37010L,37011L,37012L,
8341037013L,37014L,37015L,37016L,37017L,37018L,37019L,37020L,37021L,37022L,
8341137023L,37024L,37025L,37026L,37027L,37028L,37029L,37030L,37031L,37032L,
8341237033L,37034L,37035L,37036L,37037L,37038L,37039L,37040L,37041L,37042L,
8341337043L,37044L,37045L,37046L,37047L,37048L,37049L,37050L,37051L,37052L,
8341437053L,37054L,37055L,37056L,37057L,37058L,37059L,37060L,37061L,37062L,
8341537063L,37064L,37065L,37066L,37067L,37068L,37069L,37070L,37071L,37072L,
8341637073L,37074L,37075L,37076L,37077L,37078L,37079L,37080L,37081L,37082L,
8341737083L,37084L,37085L,37086L,37087L,37088L,37089L,37090L,37091L,37092L,
8341837093L,37094L,37095L,37096L,37097L,37098L,37099L,37100L,37101L,37102L,
8341937103L,37104L,37105L,37106L,37107L,37108L,37109L,37110L,37111L,37112L,
8342037113L,37114L,37115L,37116L,37117L,37118L,37119L,37120L,37121L,37122L,
8342137123L,37124L,37125L,37126L,37127L,37128L,37129L,37130L,37131L,37132L,
8342237133L,37134L,37135L,37136L,37137L,37138L,37139L,37140L,37141L,37142L,
8342337143L,37144L,37145L,37146L,37147L,37148L,37149L,37150L,37151L,37152L,
8342437153L,37154L,37155L,37156L,37157L,37158L,37159L,37160L,37161L,37162L,
8342537163L,37164L,37165L,37166L,37167L,37168L,37169L,37170L,37171L,37172L,
8342637173L,37174L,37175L,37176L,37177L,37178L,37179L,37180L,37181L,37182L,
8342737183L,37184L,37185L,37186L,37187L,37188L,37189L,37190L,37191L,37192L,
8342837193L,37194L,37195L,37196L,37197L,37198L,37199L,37200L,37201L,37202L,
8342937203L,37204L,37205L,37206L,37207L,37208L,37209L,37210L,37211L,37212L,
8343037213L,37214L,37215L,37216L,37217L,37218L,37219L,37220L,37221L,37222L,
8343137223L,37224L,37225L,37226L,37227L,37228L,37229L,37230L,37231L,37232L,
8343237233L,37234L,37235L,37236L,37237L,37238L,37239L,37240L,37241L,37242L,
8343337243L,37244L,37245L,37246L,37247L,37248L,37249L,37250L,37251L,37252L,
8343437253L,37254L,37255L,37256L,37257L,37258L,37259L,37260L,37261L,37262L,
8343537263L,37264L,37265L,37266L,37267L,37268L,37269L,37270L,37271L,37272L,
8343637273L,37274L,37275L,37276L,37277L,37278L,37279L,37280L,37281L,37282L,
8343737283L,37284L,37285L,37286L,37287L,37288L,37289L,37290L,37291L,37292L,
8343837293L,37294L,37295L,37296L,37297L,37298L,37299L,37300L,37301L,37302L,
8343937303L,37304L,37305L,37306L,37307L,37308L,37309L,37310L,37311L,37312L,
8344037313L,37314L,37315L,37316L,37317L,37318L,37319L,37320L,37321L,37322L,
8344137323L,37324L,37325L,37326L,37327L,37328L,37329L,37330L,37331L,37332L,
8344237333L,37334L,37335L,37336L,37337L,37338L,37339L,37340L,37341L,37342L,
8344337343L,37344L,37345L,37346L,37347L,37348L,37349L,37350L,37351L,37352L,
8344437353L,37354L,37355L,37356L,37357L,37358L,37359L,37360L,37361L,37362L,
8344537363L,37364L,37365L,37366L,37367L,37368L,37369L,37370L,37371L,37372L,
8344637373L,37374L,37375L,37376L,37377L,37378L,37379L,37380L,37381L,37382L,
8344737383L,37384L,37385L,37386L,37387L,37388L,37389L,37390L,37391L,37392L,
8344837393L,37394L,37395L,37396L,37397L,37398L,37399L,37400L,37401L,37402L,
8344937403L,37404L,37405L,37406L,37407L,37408L,37409L,37410L,37411L,37412L,
8345037413L,37414L,37415L,37416L,37417L,37418L,37419L,37420L,37421L,37422L,
8345137423L,37424L,37425L,37426L,37427L,37428L,37429L,37430L,37431L,37432L,
8345237433L,37434L,37435L,37436L,37437L,37438L,37439L,37440L,37441L,37442L,
8345337443L,37444L,37445L,37446L,37447L,37448L,37449L,37450L,37451L,37452L,
8345437453L,37454L,37455L,37456L,37457L,37458L,37459L,37460L,37461L,37462L,
8345537463L,37464L,37465L,37466L,37467L,37468L,37469L,37470L,37471L,37472L,
8345637473L,37474L,37475L,37476L,37477L,37478L,37479L,37480L,37481L,37482L,
8345737483L,37484L,37485L,37486L,37487L,37488L,37489L,37490L,37491L,37492L,
8345837493L,37494L,37495L,37496L,37497L,37498L,37499L,37500L,37501L,37502L,
8345937503L,37504L,37505L,37506L,37507L,37508L,37509L,37510L,37511L,37512L,
8346037513L,37514L,37515L,37516L,37517L,37518L,37519L,37520L,37521L,37522L,
8346137523L,37524L,37525L,37526L,37527L,37528L,37529L,37530L,37531L,37532L,
8346237533L,37534L,37535L,37536L,37537L,37538L,37539L,37540L,37541L,37542L,
8346337543L,37544L,37545L,37546L,37547L,37548L,37549L,37550L,37551L,37552L,
8346437553L,37554L,37555L,37556L,37557L,37558L,37559L,37560L,37561L,37562L,
8346537563L,37564L,37565L,37566L,37567L,37568L,37569L,37570L,37571L,37572L,
8346637573L,37574L,37575L,37576L,37577L,37578L,37579L,37580L,37581L,37582L,
8346737583L,37584L,37585L,37586L,37587L,37588L,37589L,37590L,37591L,37592L,
8346837593L,37594L,37595L,37596L,37597L,37598L,37599L,37600L,37601L,37602L,
8346937603L,37604L,37605L,37606L,37607L,37608L,37609L,37610L,37611L,37612L,
8347037613L,37614L,37615L,37616L,37617L,37618L,37619L,37620L,37621L,37622L,
8347137623L,37624L,37625L,37626L,37627L,37628L,37629L,37630L,37631L,37632L,
8347237633L,37634L,37635L,37636L,37637L,37638L,37639L,37640L,37641L,37642L,
8347337643L,37644L,37645L,37646L,37647L,37648L,37649L,37650L,37651L,37652L,
8347437653L,37654L,37655L,37656L,37657L,37658L,37659L,37660L,37661L,37662L,
8347537663L,37664L,37665L,37666L,37667L,37668L,37669L,37670L,37671L,37672L,
8347637673L,37674L,37675L,37676L,37677L,37678L,37679L,37680L,37681L,37682L,
8347737683L,37684L,37685L,37686L,37687L,37688L,37689L,37690L,37691L,37692L,
8347837693L,37694L,37695L,37696L,37697L,37698L,37699L,37700L,37701L,37702L,
8347937703L,37704L,37705L,37706L,37707L,37708L,37709L,37710L,37711L,37712L,
8348037713L,37714L,37715L,37716L,37717L,37718L,37719L,37720L,37721L,37722L,
8348137723L,37724L,37725L,37726L,37727L,37728L,37729L,37730L,37731L,37732L,
8348237733L,37734L,37735L,37736L,37737L,37738L,37739L,37740L,37741L,37742L,
8348337743L,37744L,37745L,37746L,37747L,37748L,37749L,37750L,37751L,37752L,
8348437753L,37754L,37755L,37756L,37757L,37758L,37759L,37760L,37761L,37762L,
8348537763L,37764L,37765L,37766L,37767L,37768L,37769L,37770L,37771L,37772L,
8348637773L,37774L,37775L,37776L,37777L,37778L,37779L,37780L,37781L,37782L,
8348737783L,37784L,37785L,37786L,37787L,37788L,37789L,37790L,37791L,37792L,
8348837793L,37794L,37795L,37796L,37797L,37798L,37799L,37800L,37801L,37802L,
8348937803L,37804L,37805L,37806L,37807L,37808L,37809L,37810L,37811L,37812L,
8349037813L,37814L,37815L,37816L,37817L,37818L,37819L,37820L,37821L,37822L,
8349137823L,37824L,37825L,37826L,37827L,37828L,37829L,37830L,37831L,37832L,
8349237833L,37834L,37835L,37836L,37837L,37838L,37839L,37840L,37841L,37842L,
8349337843L,37844L,37845L,37846L,37847L,37848L,37849L,37850L,37851L,37852L,
8349437853L,37854L,37855L,37856L,37857L,37858L,37859L,37860L,37861L,37862L,
8349537863L,37864L,37865L,37866L,37867L,37868L,37869L,37870L,37871L,37872L,
8349637873L,37874L,37875L,37876L,37877L,37878L,37879L,37880L,37881L,37882L,
8349737883L,37884L,37885L,37886L,37887L,37888L,37889L,37890L,37891L,37892L,
8349837893L,37894L,37895L,37896L,37897L,37898L,37899L,37900L,37901L,37902L,
8349937903L,37904L,37905L,37906L,37907L,37908L,37909L,37910L,37911L,37912L,
8350037913L,37914L,37915L,37916L,37917L,37918L,37919L,37920L,37921L,37922L,
8350137923L,37924L,37925L,37926L,37927L,37928L,37929L,37930L,37931L,37932L,
8350237933L,37934L,37935L,37936L,37937L,37938L,37939L,37940L,37941L,37942L,
8350337943L,37944L,37945L,37946L,37947L,37948L,37949L,37950L,37951L,37952L,
8350437953L,37954L,37955L,37956L,37957L,37958L,37959L,37960L,37961L,37962L,
8350537963L,37964L,37965L,37966L,37967L,37968L,37969L,37970L,37971L,37972L,
8350637973L,37974L,37975L,37976L,37977L,37978L,37979L,37980L,37981L,37982L,
8350737983L,37984L,37985L,37986L,37987L,37988L,37989L,37990L,37991L,37992L,
8350837993L,37994L,37995L,37996L,37997L,37998L,37999L,38000L,38001L,38002L,
8350938003L,38004L,38005L,38006L,38007L,38008L,38009L,38010L,38011L,38012L,
8351038013L,38014L,38015L,38016L,38017L,38018L,38019L,38020L,38021L,38022L,
8351138023L,38024L,38025L,38026L,38027L,38028L,38029L,38030L,38031L,38032L,
8351238033L,38034L,38035L,38036L,38037L,38038L,38039L,38040L,38041L,38042L,
8351338043L,38044L,38045L,38046L,38047L,38048L,38049L,38050L,38051L,38052L,
8351438053L,38054L,38055L,38056L,38057L,38058L,38059L,38060L,38061L,38062L,
8351538063L,38064L,38065L,38066L,38067L,38068L,38069L,38070L,38071L,38072L,
8351638073L,38074L,38075L,38076L,38077L,38078L,38079L,38080L,38081L,38082L,
8351738083L,38084L,38085L,38086L,38087L,38088L,38089L,38090L,38091L,38092L,
8351838093L,38094L,38095L,38096L,38097L,38098L,38099L,38100L,38101L,38102L,
8351938103L,38104L,38105L,38106L,38107L,38108L,38109L,38110L,38111L,38112L,
8352038113L,38114L,38115L,38116L,38117L,38118L,38119L,38120L,38121L,38122L,
8352138123L,38124L,38125L,38126L,38127L,38128L,38129L,38130L,38131L,38132L,
8352238133L,38134L,38135L,38136L,38137L,38138L,38139L,38140L,38141L,38142L,
8352338143L,38144L,38145L,38146L,38147L,38148L,38149L,38150L,38151L,38152L,
8352438153L,38154L,38155L,38156L,38157L,38158L,38159L,38160L,38161L,38162L,
8352538163L,38164L,38165L,38166L,38167L,38168L,38169L,38170L,38171L,38172L,
8352638173L,38174L,38175L,38176L,38177L,38178L,38179L,38180L,38181L,38182L,
8352738183L,38184L,38185L,38186L,38187L,38188L,38189L,38190L,38191L,38192L,
8352838193L,38194L,38195L,38196L,38197L,38198L,38199L,38200L,38201L,38202L,
8352938203L,38204L,38205L,38206L,38207L,38208L,38209L,38210L,38211L,38212L,
8353038213L,38214L,38215L,38216L,38217L,38218L,38219L,38220L,38221L,38222L,
8353138223L,38224L,38225L,38226L,38227L,38228L,38229L,38230L,38231L,38232L,
8353238233L,38234L,38235L,38236L,38237L,38238L,38239L,38240L,38241L,38242L,
8353338243L,38244L,38245L,38246L,38247L,38248L,38249L,38250L,38251L,38252L,
8353438253L,38254L,38255L,38256L,38257L,38258L,38259L,38260L,38261L,38262L,
8353538263L,38264L,38265L,38266L,38267L,38268L,38269L,38270L,38271L,38272L,
8353638273L,38274L,38275L,38276L,38277L,38278L,38279L,38280L,38281L,38282L,
8353738283L,38284L,38285L,38286L,38287L,38288L,38289L,38290L,38291L,38292L,
8353838293L,38294L,38295L,38296L,38297L,38298L,38299L,38300L,38301L,38302L,
8353938303L,38304L,38305L,38306L,38307L,38308L,38309L,38310L,38311L,38312L,
8354038313L,38314L,38315L,38316L,38317L,38318L,38319L,38320L,38321L,38322L,
8354138323L,38324L,38325L,38326L,38327L,38328L,38329L,38330L,38331L,38332L,
8354238333L,38334L,38335L,38336L,38337L,38338L,38339L,38340L,38341L,38342L,
8354338343L,38344L,38345L,38346L,38347L,38348L,38349L,38350L,38351L,38352L,
8354438353L,38354L,38355L,38356L,38357L,38358L,38359L,38360L,38361L,38362L,
8354538363L,38364L,38365L,38366L,38367L,38368L,38369L,38370L,38371L,38372L,
8354638373L,38374L,38375L,38376L,38377L,38378L,38379L,38380L,38381L,38382L,
8354738383L,38384L,38385L,38386L,38387L,38388L,38389L,38390L,38391L,38392L,
8354838393L,38394L,38395L,38396L,38397L,38398L,38399L,38400L,38401L,38402L,
8354938403L,38404L,38405L,38406L,38407L,38408L,38409L,38410L,38411L,38412L,
8355038413L,38414L,38415L,38416L,38417L,38418L,38419L,38420L,38421L,38422L,
8355138423L,38424L,38425L,38426L,38427L,38428L,38429L,38430L,38431L,38432L,
8355238433L,38434L,38435L,38436L,38437L,38438L,38439L,38440L,38441L,38442L,
8355338443L,38444L,38445L,38446L,38447L,38448L,38449L,38450L,38451L,38452L,
8355438453L,38454L,38455L,38456L,38457L,38458L,38459L,38460L,38461L,38462L,
8355538463L,38464L,38465L,38466L,38467L,38468L,38469L,38470L,38471L,38472L,
8355638473L,38474L,38475L,38476L,38477L,38478L,38479L,38480L,38481L,38482L,
8355738483L,38484L,38485L,38486L,38487L,38488L,38489L,38490L,38491L,38492L,
8355838493L,38494L,38495L,38496L,38497L,38498L,38499L,38500L,38501L,38502L,
8355938503L,38504L,38505L,38506L,38507L,38508L,38509L,38510L,38511L,38512L,
8356038513L,38514L,38515L,38516L,38517L,38518L,38519L,38520L,38521L,38522L,
8356138523L,38524L,38525L,38526L,38527L,38528L,38529L,38530L,38531L,38532L,
8356238533L,38534L,38535L,38536L,38537L,38538L,38539L,38540L,38541L,38542L,
8356338543L,38544L,38545L,38546L,38547L,38548L,38549L,38550L,38551L,38552L,
8356438553L,38554L,38555L,38556L,38557L,38558L,38559L,38560L,38561L,38562L,
8356538563L,38564L,38565L,38566L,38567L,38568L,38569L,38570L,38571L,38572L,
8356638573L,38574L,38575L,38576L,38577L,38578L,38579L,38580L,38581L,38582L,
8356738583L,38584L,38585L,38586L,38587L,38588L,38589L,38590L,38591L,38592L,
8356838593L,38594L,38595L,38596L,38597L,38598L,38599L,38600L,38601L,38602L,
8356938603L,38604L,38605L,38606L,38607L,38608L,38609L,38610L,38611L,38612L,
8357038613L,38614L,38615L,38616L,38617L,38618L,38619L,38620L,38621L,38622L,
8357138623L,38624L,38625L,38626L,38627L,38628L,38629L,38630L,38631L,38632L,
8357238633L,38634L,38635L,38636L,38637L,38638L,38639L,38640L,38641L,38642L,
8357338643L,38644L,38645L,38646L,38647L,38648L,38649L,38650L,38651L,38652L,
8357438653L,38654L,38655L,38656L,38657L,38658L,38659L,38660L,38661L,38662L,
8357538663L,38664L,38665L,38666L,38667L,38668L,38669L,38670L,38671L,38672L,
8357638673L,38674L,38675L,38676L,38677L,38678L,38679L,38680L,38681L,38682L,
8357738683L,38684L,38685L,38686L,38687L,38688L,38689L,38690L,38691L,38692L,
8357838693L,38694L,38695L,38696L,38697L,38698L,38699L,38700L,38701L,38702L,
8357938703L,38704L,38705L,38706L,38707L,38708L,38709L,38710L,38711L,38712L,
8358038713L,38714L,38715L,38716L,38717L,38718L,38719L,38720L,38721L,38722L,
8358138723L,38724L,38725L,38726L,38727L,38728L,38729L,38730L,38731L,38732L,
8358238733L,38734L,38735L,38736L,38737L,38738L,38739L,38740L,38741L,38742L,
8358338743L,38744L,38745L,38746L,38747L,38748L,38749L,38750L,38751L,38752L,
8358438753L,38754L,38755L,38756L,38757L,38758L,38759L,38760L,38761L,38762L,
8358538763L,38764L,38765L,38766L,38767L,38768L,38769L,38770L,38771L,38772L,
8358638773L,38774L,38775L,38776L,38777L,38778L,38779L,38780L,38781L,38782L,
8358738783L,38784L,38785L,38786L,38787L,38788L,38789L,38790L,38791L,38792L,
8358838793L,38794L,38795L,38796L,38797L,38798L,38799L,38800L,38801L,38802L,
8358938803L,38804L,38805L,38806L,38807L,38808L,38809L,38810L,38811L,38812L,
8359038813L,38814L,38815L,38816L,38817L,38818L,38819L,38820L,38821L,38822L,
8359138823L,38824L,38825L,38826L,38827L,38828L,38829L,38830L,38831L,38832L,
8359238833L,38834L,38835L,38836L,38837L,38838L,38839L,38840L,38841L,38842L,
8359338843L,38844L,38845L,38846L,38847L,38848L,38849L,38850L,38851L,38852L,
8359438853L,38854L,38855L,38856L,38857L,38858L,38859L,38860L,38861L,38862L,
8359538863L,38864L,38865L,38866L,38867L,38868L,38869L,38870L,38871L,38872L,
8359638873L,38874L,38875L,38876L,38877L,38878L,38879L,38880L,38881L,38882L,
8359738883L,38884L,38885L,38886L,38887L,38888L,38889L,38890L,38891L,38892L,
8359838893L,38894L,38895L,38896L,38897L,38898L,38899L,38900L,38901L,38902L,
8359938903L,38904L,38905L,38906L,38907L,38908L,38909L,38910L,38911L,38912L,
8360038913L,38914L,38915L,38916L,38917L,38918L,38919L,38920L,38921L,38922L,
8360138923L,38924L,38925L,38926L,38927L,38928L,38929L,38930L,38931L,38932L,
8360238933L,38934L,38935L,38936L,38937L,38938L,38939L,38940L,38941L,38942L,
8360338943L,38944L,38945L,38946L,38947L,38948L,38949L,38950L,38951L,38952L,
8360438953L,38954L,38955L,38956L,38957L,38958L,38959L,38960L,38961L,38962L,
8360538963L,38964L,38965L,38966L,38967L,38968L,38969L,38970L,38971L,38972L,
8360638973L,38974L,38975L,38976L,38977L,38978L,38979L,38980L,38981L,38982L,
8360738983L,38984L,38985L,38986L,38987L,38988L,38989L,38990L,38991L,38992L,
8360838993L,38994L,38995L,38996L,38997L,38998L,38999L,39000L,39001L,39002L,
8360939003L,39004L,39005L,39006L,39007L,39008L,39009L,39010L,39011L,39012L,
8361039013L,39014L,39015L,39016L,39017L,39018L,39019L,39020L,39021L,39022L,
8361139023L,39024L,39025L,39026L,39027L,39028L,39029L,39030L,39031L,39032L,
8361239033L,39034L,39035L,39036L,39037L,39038L,39039L,39040L,39041L,39042L,
8361339043L,39044L,39045L,39046L,39047L,39048L,39049L,39050L,39051L,39052L,
8361439053L,39054L,39055L,39056L,39057L,39058L,39059L,39060L,39061L,39062L,
8361539063L,39064L,39065L,39066L,39067L,39068L,39069L,39070L,39071L,39072L,
8361639073L,39074L,39075L,39076L,39077L,39078L,39079L,39080L,39081L,39082L,
8361739083L,39084L,39085L,39086L,39087L,39088L,39089L,39090L,39091L,39092L,
8361839093L,39094L,39095L,39096L,39097L,39098L,39099L,39100L,39101L,39102L,
8361939103L,39104L,39105L,39106L,39107L,39108L,39109L,39110L,39111L,39112L,
8362039113L,39114L,39115L,39116L,39117L,39118L,39119L,39120L,39121L,39122L,
8362139123L,39124L,39125L,39126L,39127L,39128L,39129L,39130L,39131L,39132L,
8362239133L,39134L,39135L,39136L,39137L,39138L,39139L,39140L,39141L,39142L,
8362339143L,39144L,39145L,39146L,39147L,39148L,39149L,39150L,39151L,39152L,
8362439153L,39154L,39155L,39156L,39157L,39158L,39159L,39160L,39161L,39162L,
8362539163L,39164L,39165L,39166L,39167L,39168L,39169L,39170L,39171L,39172L,
8362639173L,39174L,39175L,39176L,39177L,39178L,39179L,39180L,39181L,39182L,
8362739183L,39184L,39185L,39186L,39187L,39188L,39189L,39190L,39191L,39192L,
8362839193L,39194L,39195L,39196L,39197L,39198L,39199L,39200L,39201L,39202L,
8362939203L,39204L,39205L,39206L,39207L,39208L,39209L,39210L,39211L,39212L,
8363039213L,39214L,39215L,39216L,39217L,39218L,39219L,39220L,39221L,39222L,
8363139223L,39224L,39225L,39226L,39227L,39228L,39229L,39230L,39231L,39232L,
8363239233L,39234L,39235L,39236L,39237L,39238L,39239L,39240L,39241L,39242L,
8363339243L,39244L,39245L,39246L,39247L,39248L,39249L,39250L,39251L,39252L,
8363439253L,39254L,39255L,39256L,39257L,39258L,39259L,39260L,39261L,39262L,
8363539263L,39264L,39265L,39266L,39267L,39268L,39269L,39270L,39271L,39272L,
8363639273L,39274L,39275L,39276L,39277L,39278L,39279L,39280L,39281L,39282L,
8363739283L,39284L,39285L,39286L,39287L,39288L,39289L,39290L,39291L,39292L,
8363839293L,39294L,39295L,39296L,39297L,39298L,39299L,39300L,39301L,39302L,
8363939303L,39304L,39305L,39306L,39307L,39308L,39309L,39310L,39311L,39312L,
8364039313L,39314L,39315L,39316L,39317L,39318L,39319L,39320L,39321L,39322L,
8364139323L,39324L,39325L,39326L,39327L,39328L,39329L,39330L,39331L,39332L,
8364239333L,39334L,39335L,39336L,39337L,39338L,39339L,39340L,39341L,39342L,
8364339343L,39344L,39345L,39346L,39347L,39348L,39349L,39350L,39351L,39352L,
8364439353L,39354L,39355L,39356L,39357L,39358L,39359L,39360L,39361L,39362L,
8364539363L,39364L,39365L,39366L,39367L,39368L,39369L,39370L,39371L,39372L,
8364639373L,39374L,39375L,39376L,39377L,39378L,39379L,39380L,39381L,39382L,
8364739383L,39384L,39385L,39386L,39387L,39388L,39389L,39390L,39391L,39392L,
8364839393L,39394L,39395L,39396L,39397L,39398L,39399L,39400L,39401L,39402L,
8364939403L,39404L,39405L,39406L,39407L,39408L,39409L,39410L,39411L,39412L,
8365039413L,39414L,39415L,39416L,39417L,39418L,39419L,39420L,39421L,39422L,
8365139423L,39424L,39425L,39426L,39427L,39428L,39429L,39430L,39431L,39432L,
8365239433L,39434L,39435L,39436L,39437L,39438L,39439L,39440L,39441L,39442L,
8365339443L,39444L,39445L,39446L,39447L,39448L,39449L,39450L,39451L,39452L,
8365439453L,39454L,39455L,39456L,39457L,39458L,39459L,39460L,39461L,39462L,
8365539463L,39464L,39465L,39466L,39467L,39468L,39469L,39470L,39471L,39472L,
8365639473L,39474L,39475L,39476L,39477L,39478L,39479L,39480L,39481L,39482L,
8365739483L,39484L,39485L,39486L,39487L,39488L,39489L,39490L,39491L,39492L,
8365839493L,39494L,39495L,39496L,39497L,39498L,39499L,39500L,39501L,39502L,
8365939503L,39504L,39505L,39506L,39507L,39508L,39509L,39510L,39511L,39512L,
8366039513L,39514L,39515L,39516L,39517L,39518L,39519L,39520L,39521L,39522L,
8366139523L,39524L,39525L,39526L,39527L,39528L,39529L,39530L,39531L,39532L,
8366239533L,39534L,39535L,39536L,39537L,39538L,39539L,39540L,39541L,39542L,
8366339543L,39544L,39545L,39546L,39547L,39548L,39549L,39550L,39551L,39552L,
8366439553L,39554L,39555L,39556L,39557L,39558L,39559L,39560L,39561L,39562L,
8366539563L,39564L,39565L,39566L,39567L,39568L,39569L,39570L,39571L,39572L,
8366639573L,39574L,39575L,39576L,39577L,39578L,39579L,39580L,39581L,39582L,
8366739583L,39584L,39585L,39586L,39587L,39588L,39589L,39590L,39591L,39592L,
8366839593L,39594L,39595L,39596L,39597L,39598L,39599L,39600L,39601L,39602L,
8366939603L,39604L,39605L,39606L,39607L,39608L,39609L,39610L,39611L,39612L,
8367039613L,39614L,39615L,39616L,39617L,39618L,39619L,39620L,39621L,39622L,
8367139623L,39624L,39625L,39626L,39627L,39628L,39629L,39630L,39631L,39632L,
8367239633L,39634L,39635L,39636L,39637L,39638L,39639L,39640L,39641L,39642L,
8367339643L,39644L,39645L,39646L,39647L,39648L,39649L,39650L,39651L,39652L,
8367439653L,39654L,39655L,39656L,39657L,39658L,39659L,39660L,39661L,39662L,
8367539663L,39664L,39665L,39666L,39667L,39668L,39669L,39670L,39671L,39672L,
8367639673L,39674L,39675L,39676L,39677L,39678L,39679L,39680L,39681L,39682L,
8367739683L,39684L,39685L,39686L,39687L,39688L,39689L,39690L,39691L,39692L,
8367839693L,39694L,39695L,39696L,39697L,39698L,39699L,39700L,39701L,39702L,
8367939703L,39704L,39705L,39706L,39707L,39708L,39709L,39710L,39711L,39712L,
8368039713L,39714L,39715L,39716L,39717L,39718L,39719L,39720L,39721L,39722L,
8368139723L,39724L,39725L,39726L,39727L,39728L,39729L,39730L,39731L,39732L,
8368239733L,39734L,39735L,39736L,39737L,39738L,39739L,39740L,39741L,39742L,
8368339743L,39744L,39745L,39746L,39747L,39748L,39749L,39750L,39751L,39752L,
8368439753L,39754L,39755L,39756L,39757L,39758L,39759L,39760L,39761L,39762L,
8368539763L,39764L,39765L,39766L,39767L,39768L,39769L,39770L,39771L,39772L,
8368639773L,39774L,39775L,39776L,39777L,39778L,39779L,39780L,39781L,39782L,
8368739783L,39784L,39785L,39786L,39787L,39788L,39789L,39790L,39791L,39792L,
8368839793L,39794L,39795L,39796L,39797L,39798L,39799L,39800L,39801L,39802L,
8368939803L,39804L,39805L,39806L,39807L,39808L,39809L,39810L,39811L,39812L,
8369039813L,39814L,39815L,39816L,39817L,39818L,39819L,39820L,39821L,39822L,
8369139823L,39824L,39825L,39826L,39827L,39828L,39829L,39830L,39831L,39832L,
8369239833L,39834L,39835L,39836L,39837L,39838L,39839L,39840L,39841L,39842L,
8369339843L,39844L,39845L,39846L,39847L,39848L,39849L,39850L,39851L,39852L,
8369439853L,39854L,39855L,39856L,39857L,39858L,39859L,39860L,39861L,39862L,
8369539863L,39864L,39865L,39866L,39867L,39868L,39869L,39870L,39871L,39872L,
8369639873L,39874L,39875L,39876L,39877L,39878L,39879L,39880L,39881L,39882L,
8369739883L,39884L,39885L,39886L,39887L,39888L,39889L,39890L,39891L,39892L,
8369839893L,39894L,39895L,39896L,39897L,39898L,39899L,39900L,39901L,39902L,
8369939903L,39904L,39905L,39906L,39907L,39908L,39909L,39910L,39911L,39912L,
8370039913L,39914L,39915L,39916L,39917L,39918L,39919L,39920L,39921L,39922L,
8370139923L,39924L,39925L,39926L,39927L,39928L,39929L,39930L,39931L,39932L,
8370239933L,39934L,39935L,39936L,39937L,39938L,39939L,39940L,39941L,39942L,
8370339943L,39944L,39945L,39946L,39947L,39948L,39949L,39950L,39951L,39952L,
8370439953L,39954L,39955L,39956L,39957L,39958L,39959L,39960L,39961L,39962L,
8370539963L,39964L,39965L,39966L,39967L,39968L,39969L,39970L,39971L,39972L,
8370639973L,39974L,39975L,39976L,39977L,39978L,39979L,39980L,39981L,39982L,
8370739983L,39984L,39985L,39986L,39987L,39988L,39989L,39990L,39991L,39992L,
8370839993L,39994L,39995L,39996L,39997L,39998L,39999L,40000L,40001L,40002L,
8370940003L,40004L,40005L,40006L,40007L,40008L,40009L,40010L,40011L,40012L,
8371040013L,40014L,40015L,40016L,40017L,40018L,40019L,40020L,40021L,40022L,
8371140023L,40024L,40025L,40026L,40027L,40028L,40029L,40030L,40031L,40032L,
8371240033L,40034L,40035L,40036L,40037L,40038L,40039L,40040L,40041L,40042L,
8371340043L,40044L,40045L,40046L,40047L,40048L,40049L,40050L,40051L,40052L,
8371440053L,40054L,40055L,40056L,40057L,40058L,40059L,40060L,40061L,40062L,
8371540063L,40064L,40065L,40066L,40067L,40068L,40069L,40070L,40071L,40072L,
8371640073L,40074L,40075L,40076L,40077L,40078L,40079L,40080L,40081L,40082L,
8371740083L,40084L,40085L,40086L,40087L,40088L,40089L,40090L,40091L,40092L,
8371840093L,40094L,40095L,40096L,40097L,40098L,40099L,40100L,40101L,40102L,
8371940103L,40104L,40105L,40106L,40107L,40108L,40109L,40110L,40111L,40112L,
8372040113L,40114L,40115L,40116L,40117L,40118L,40119L,40120L,40121L,40122L,
8372140123L,40124L,40125L,40126L,40127L,40128L,40129L,40130L,40131L,40132L,
8372240133L,40134L,40135L,40136L,40137L,40138L,40139L,40140L,40141L,40142L,
8372340143L,40144L,40145L,40146L,40147L,40148L,40149L,40150L,40151L,40152L,
8372440153L,40154L,40155L,40156L,40157L,40158L,40159L,40160L,40161L,40162L,
8372540163L,40164L,40165L,40166L,40167L,40168L,40169L,40170L,40171L,40172L,
8372640173L,40174L,40175L,40176L,40177L,40178L,40179L,40180L,40181L,40182L,
8372740183L,40184L,40185L,40186L,40187L,40188L,40189L,40190L,40191L,40192L,
8372840193L,40194L,40195L,40196L,40197L,40198L,40199L,40200L,40201L,40202L,
8372940203L,40204L,40205L,40206L,40207L,40208L,40209L,40210L,40211L,40212L,
8373040213L,40214L,40215L,40216L,40217L,40218L,40219L,40220L,40221L,40222L,
8373140223L,40224L,40225L,40226L,40227L,40228L,40229L,40230L,40231L,40232L,
8373240233L,40234L,40235L,40236L,40237L,40238L,40239L,40240L,40241L,40242L,
8373340243L,40244L,40245L,40246L,40247L,40248L,40249L,40250L,40251L,40252L,
8373440253L,40254L,40255L,40256L,40257L,40258L,40259L,40260L,40261L,40262L,
8373540263L,40264L,40265L,40266L,40267L,40268L,40269L,40270L,40271L,40272L,
8373640273L,40274L,40275L,40276L,40277L,40278L,40279L,40280L,40281L,40282L,
8373740283L,40284L,40285L,40286L,40287L,40288L,40289L,40290L,40291L,40292L,
8373840293L,40294L,40295L,40296L,40297L,40298L,40299L,40300L,40301L,40302L,
8373940303L,40304L,40305L,40306L,40307L,40308L,40309L,40310L,40311L,40312L,
8374040313L,40314L,40315L,40316L,40317L,40318L,40319L,40320L,40321L,40322L,
8374140323L,40324L,40325L,40326L,40327L,40328L,40329L,40330L,40331L,40332L,
8374240333L,40334L,40335L,40336L,40337L,40338L,40339L,40340L,40341L,40342L,
8374340343L,40344L,40345L,40346L,40347L,40348L,40349L,40350L,40351L,40352L,
8374440353L,40354L,40355L,40356L,40357L,40358L,40359L,40360L,40361L,40362L,
8374540363L,40364L,40365L,40366L,40367L,40368L,40369L,40370L,40371L,40372L,
8374640373L,40374L,40375L,40376L,40377L,40378L,40379L,40380L,40381L,40382L,
8374740383L,40384L,40385L,40386L,40387L,40388L,40389L,40390L,40391L,40392L,
8374840393L,40394L,40395L,40396L,40397L,40398L,40399L,40400L,40401L,40402L,
8374940403L,40404L,40405L,40406L,40407L,40408L,40409L,40410L,40411L,40412L,
8375040413L,40414L,40415L,40416L,40417L,40418L,40419L,40420L,40421L,40422L,
8375140423L,40424L,40425L,40426L,40427L,40428L,40429L,40430L,40431L,40432L,
8375240433L,40434L,40435L,40436L,40437L,40438L,40439L,40440L,40441L,40442L,
8375340443L,40444L,40445L,40446L,40447L,40448L,40449L,40450L,40451L,40452L,
8375440453L,40454L,40455L,40456L,40457L,40458L,40459L,40460L,40461L,40462L,
8375540463L,40464L,40465L,40466L,40467L,40468L,40469L,40470L,40471L,40472L,
8375640473L,40474L,40475L,40476L,40477L,40478L,40479L,40480L,40481L,40482L,
8375740483L,40484L,40485L,40486L,40487L,40488L,40489L,40490L,40491L,40492L,
8375840493L,40494L,40495L,40496L,40497L,40498L,40499L,40500L,40501L,40502L,
8375940503L,40504L,40505L,40506L,40507L,40508L,40509L,40510L,40511L,40512L,
8376040513L,40514L,40515L,40516L,40517L,40518L,40519L,40520L,40521L,40522L,
8376140523L,40524L,40525L,40526L,40527L,40528L,40529L,40530L,40531L,40532L,
8376240533L,40534L,40535L,40536L,40537L,40538L,40539L,40540L,40541L,40542L,
8376340543L,40544L,40545L,40546L,40547L,40548L,40549L,40550L,40551L,40552L,
8376440553L,40554L,40555L,40556L,40557L,40558L,40559L,40560L,40561L,40562L,
8376540563L,40564L,40565L,40566L,40567L,40568L,40569L,40570L,40571L,40572L,
8376640573L,40574L,40575L,40576L,40577L,40578L,40579L,40580L,40581L,40582L,
8376740583L,40584L,40585L,40586L,40587L,40588L,40589L,40590L,40591L,40592L,
8376840593L,40594L,40595L,40596L,40597L,40598L,40599L,40600L,40601L,40602L,
8376940603L,40604L,40605L,40606L,40607L,40608L,40609L,40610L,40611L,40612L,
8377040613L,40614L,40615L,40616L,40617L,40618L,40619L,40620L,40621L,40622L,
8377140623L,40624L,40625L,40626L,40627L,40628L,40629L,40630L,40631L,40632L,
8377240633L,40634L,40635L,40636L,40637L,40638L,40639L,40640L,40641L,40642L,
8377340643L,40644L,40645L,40646L,40647L,40648L,40649L,40650L,40651L,40652L,
8377440653L,40654L,40655L,40656L,40657L,40658L,40659L,40660L,40661L,40662L,
8377540663L,40664L,40665L,40666L,40667L,40668L,40669L,40670L,40671L,40672L,
8377640673L,40674L,40675L,40676L,40677L,40678L,40679L,40680L,40681L,40682L,
8377740683L,40684L,40685L,40686L,40687L,40688L,40689L,40690L,40691L,40692L,
8377840693L,40694L,40695L,40696L,40697L,40698L,40699L,40700L,40701L,40702L,
8377940703L,40704L,40705L,40706L,40707L,40708L,40709L,40710L,40711L,40712L,
8378040713L,40714L,40715L,40716L,40717L,40718L,40719L,40720L,40721L,40722L,
8378140723L,40724L,40725L,40726L,40727L,40728L,40729L,40730L,40731L,40732L,
8378240733L,40734L,40735L,40736L,40737L,40738L,40739L,40740L,40741L,40742L,
8378340743L,40744L,40745L,40746L,40747L,40748L,40749L,40750L,40751L,40752L,
8378440753L,40754L,40755L,40756L,40757L,40758L,40759L,40760L,40761L,40762L,
8378540763L,40764L,40765L,40766L,40767L,40768L,40769L,40770L,40771L,40772L,
8378640773L,40774L,40775L,40776L,40777L,40778L,40779L,40780L,40781L,40782L,
8378740783L,40784L,40785L,40786L,40787L,40788L,40789L,40790L,40791L,40792L,
8378840793L,40794L,40795L,40796L,40797L,40798L,40799L,40800L,40801L,40802L,
8378940803L,40804L,40805L,40806L,40807L,40808L,40809L,40810L,40811L,40812L,
8379040813L,40814L,40815L,40816L,40817L,40818L,40819L,40820L,40821L,40822L,
8379140823L,40824L,40825L,40826L,40827L,40828L,40829L,40830L,40831L,40832L,
8379240833L,40834L,40835L,40836L,40837L,40838L,40839L,40840L,40841L,40842L,
8379340843L,40844L,40845L,40846L,40847L,40848L,40849L,40850L,40851L,40852L,
8379440853L,40854L,40855L,40856L,40857L,40858L,40859L,40860L,40861L,40862L,
8379540863L,40864L,40865L,40866L,40867L,40868L,40869L,40870L,40871L,40872L,
8379640873L,40874L,40875L,40876L,40877L,40878L,40879L,40880L,40881L,40882L,
8379740883L,40884L,40885L,40886L,40887L,40888L,40889L,40890L,40891L,40892L,
8379840893L,40894L,40895L,40896L,40897L,40898L,40899L,40900L,40901L,40902L,
8379940903L,40904L,40905L,40906L,40907L,40908L,40909L,40910L,40911L,40912L,
8380040913L,40914L,40915L,40916L,40917L,40918L,40919L,40920L,40921L,40922L,
8380140923L,40924L,40925L,40926L,40927L,40928L,40929L,40930L,40931L,40932L,
8380240933L,40934L,40935L,40936L,40937L,40938L,40939L,40940L,40941L,40942L,
8380340943L,40944L,40945L,40946L,40947L,40948L,40949L,40950L,40951L,40952L,
8380440953L,40954L,40955L,40956L,40957L,40958L,40959L,40960L,40961L,40962L,
8380540963L,40964L,40965L,40966L,40967L,40968L,40969L,40970L,40971L,40972L,
8380640973L,40974L,40975L,40976L,40977L,40978L,40979L,40980L,40981L,40982L,
8380740983L,40984L,40985L,40986L,40987L,40988L,40989L,40990L,40991L,40992L,
8380840993L,40994L,40995L,40996L,40997L,40998L,40999L,41000L,41001L,41002L,
8380941003L,41004L,41005L,41006L,41007L,41008L,41009L,41010L,41011L,41012L,
8381041013L,41014L,41015L,41016L,41017L,41018L,41019L,41020L,41021L,41022L,
8381141023L,41024L,41025L,41026L,41027L,41028L,41029L,41030L,41031L,41032L,
8381241033L,41034L,41035L,41036L,41037L,41038L,41039L,41040L,41041L,41042L,
8381341043L,41044L,41045L,41046L,41047L,41048L,41049L,41050L,41051L,41052L,
8381441053L,41054L,41055L,41056L,41057L,41058L,41059L,41060L,41061L,41062L,
8381541063L,41064L,41065L,41066L,41067L,41068L,41069L,41070L,41071L,41072L,
8381641073L,41074L,41075L,41076L,41077L,41078L,41079L,41080L,41081L,41082L,
8381741083L,41084L,41085L,41086L,41087L,41088L,41089L,41090L,41091L,41092L,
8381841093L,41094L,41095L,41096L,41097L,41098L,41099L,41100L,41101L,41102L,
8381941103L,41104L,41105L,41106L,41107L,41108L,41109L,41110L,41111L,41112L,
8382041113L,41114L,41115L,41116L,41117L,41118L,41119L,41120L,41121L,41122L,
8382141123L,41124L,41125L,41126L,41127L,41128L,41129L,41130L,41131L,41132L,
8382241133L,41134L,41135L,41136L,41137L,41138L,41139L,41140L,41141L,41142L,
8382341143L,41144L,41145L,41146L,41147L,41148L,41149L,41150L,41151L,41152L,
8382441153L,41154L,41155L,41156L,41157L,41158L,41159L,41160L,41161L,41162L,
8382541163L,41164L,41165L,41166L,41167L,41168L,41169L,41170L,41171L,41172L,
8382641173L,41174L,41175L,41176L,41177L,41178L,41179L,41180L,41181L,41182L,
8382741183L,41184L,41185L,41186L,41187L,41188L,41189L,41190L,41191L,41192L,
8382841193L,41194L,41195L,41196L,41197L,41198L,41199L,41200L,41201L,41202L,
8382941203L,41204L,41205L,41206L,41207L,41208L,41209L,41210L,41211L,41212L,
8383041213L,41214L,41215L,41216L,41217L,41218L,41219L,41220L,41221L,41222L,
8383141223L,41224L,41225L,41226L,41227L,41228L,41229L,41230L,41231L,41232L,
8383241233L,41234L,41235L,41236L,41237L,41238L,41239L,41240L,41241L,41242L,
8383341243L,41244L,41245L,41246L,41247L,41248L,41249L,41250L,41251L,41252L,
8383441253L,41254L,41255L,41256L,41257L,41258L,41259L,41260L,41261L,41262L,
8383541263L,41264L,41265L,41266L,41267L,41268L,41269L,41270L,41271L,41272L,
8383641273L,41274L,41275L,41276L,41277L,41278L,41279L,41280L,41281L,41282L,
8383741283L,41284L,41285L,41286L,41287L,41288L,41289L,41290L,41291L,41292L,
8383841293L,41294L,41295L,41296L,41297L,41298L,41299L,41300L,41301L,41302L,
8383941303L,41304L,41305L,41306L,41307L,41308L,41309L,41310L,41311L,41312L,
8384041313L,41314L,41315L,41316L,41317L,41318L,41319L,41320L,41321L,41322L,
8384141323L,41324L,41325L,41326L,41327L,41328L,41329L,41330L,41331L,41332L,
8384241333L,41334L,41335L,41336L,41337L,41338L,41339L,41340L,41341L,41342L,
8384341343L,41344L,41345L,41346L,41347L,41348L,41349L,41350L,41351L,41352L,
8384441353L,41354L,41355L,41356L,41357L,41358L,41359L,41360L,41361L,41362L,
8384541363L,41364L,41365L,41366L,41367L,41368L,41369L,41370L,41371L,41372L,
8384641373L,41374L,41375L,41376L,41377L,41378L,41379L,41380L,41381L,41382L,
8384741383L,41384L,41385L,41386L,41387L,41388L,41389L,41390L,41391L,41392L,
8384841393L,41394L,41395L,41396L,41397L,41398L,41399L,41400L,41401L,41402L,
8384941403L,41404L,41405L,41406L,41407L,41408L,41409L,41410L,41411L,41412L,
8385041413L,41414L,41415L,41416L,41417L,41418L,41419L,41420L,41421L,41422L,
8385141423L,41424L,41425L,41426L,41427L,41428L,41429L,41430L,41431L,41432L,
8385241433L,41434L,41435L,41436L,41437L,41438L,41439L,41440L,41441L,41442L,
8385341443L,41444L,41445L,41446L,41447L,41448L,41449L,41450L,41451L,41452L,
8385441453L,41454L,41455L,41456L,41457L,41458L,41459L,41460L,41461L,41462L,
8385541463L,41464L,41465L,41466L,41467L,41468L,41469L,41470L,41471L,41472L,
8385641473L,41474L,41475L,41476L,41477L,41478L,41479L,41480L,41481L,41482L,
8385741483L,41484L,41485L,41486L,41487L,41488L,41489L,41490L,41491L,41492L,
8385841493L,41494L,41495L,41496L,41497L,41498L,41499L,41500L,41501L,41502L,
8385941503L,41504L,41505L,41506L,41507L,41508L,41509L,41510L,41511L,41512L,
8386041513L,41514L,41515L,41516L,41517L,41518L,41519L,41520L,41521L,41522L,
8386141523L,41524L,41525L,41526L,41527L,41528L,41529L,41530L,41531L,41532L,
8386241533L,41534L,41535L,41536L,41537L,41538L,41539L,41540L,41541L,41542L,
8386341543L,41544L,41545L,41546L,41547L,41548L,41549L,41550L,41551L,41552L,
8386441553L,41554L,41555L,41556L,41557L,41558L,41559L,41560L,41561L,41562L,
8386541563L,41564L,41565L,41566L,41567L,41568L,41569L,41570L,41571L,41572L,
8386641573L,41574L,41575L,41576L,41577L,41578L,41579L,41580L,41581L,41582L,
8386741583L,41584L,41585L,41586L,41587L,41588L,41589L,41590L,41591L,41592L,
8386841593L,41594L,41595L,41596L,41597L,41598L,41599L,41600L,41601L,41602L,
8386941603L,41604L,41605L,41606L,41607L,41608L,41609L,41610L,41611L,41612L,
8387041613L,41614L,41615L,41616L,41617L,41618L,41619L,41620L,41621L,41622L,
8387141623L,41624L,41625L,41626L,41627L,41628L,41629L,41630L,41631L,41632L,
8387241633L,41634L,41635L,41636L,41637L,41638L,41639L,41640L,41641L,41642L,
8387341643L,41644L,41645L,41646L,41647L,41648L,41649L,41650L,41651L,41652L,
8387441653L,41654L,41655L,41656L,41657L,41658L,41659L,41660L,41661L,41662L,
8387541663L,41664L,41665L,41666L,41667L,41668L,41669L,41670L,41671L,41672L,
8387641673L,41674L,41675L,41676L,41677L,41678L,41679L,41680L,41681L,41682L,
8387741683L,41684L,41685L,41686L,41687L,41688L,41689L,41690L,41691L,41692L,
8387841693L,41694L,41695L,41696L,41697L,41698L,41699L,41700L,41701L,41702L,
8387941703L,41704L,41705L,41706L,41707L,41708L,41709L,41710L,41711L,41712L,
8388041713L,41714L,41715L,41716L,41717L,41718L,41719L,41720L,41721L,41722L,
8388141723L,41724L,41725L,41726L,41727L,41728L,41729L,41730L,41731L,41732L,
8388241733L,41734L,41735L,41736L,41737L,41738L,41739L,41740L,41741L,41742L,
8388341743L,41744L,41745L,41746L,41747L,41748L,41749L,41750L,41751L,41752L,
8388441753L,41754L,41755L,41756L,41757L,41758L,41759L,41760L,41761L,41762L,
8388541763L,41764L,41765L,41766L,41767L,41768L,41769L,41770L,41771L,41772L,
8388641773L,41774L,41775L,41776L,41777L,41778L,41779L,41780L,41781L,41782L,
8388741783L,41784L,41785L,41786L,41787L,41788L,41789L,41790L,41791L,41792L,
8388841793L,41794L,41795L,41796L,41797L,41798L,41799L,41800L,41801L,41802L,
8388941803L,41804L,41805L,41806L,41807L,41808L,41809L,41810L,41811L,41812L,
8389041813L,41814L,41815L,41816L,41817L,41818L,41819L,41820L,41821L,41822L,
8389141823L,41824L,41825L,41826L,41827L,41828L,41829L,41830L,41831L,41832L,
8389241833L,41834L,41835L,41836L,41837L,41838L,41839L,41840L,41841L,41842L,
8389341843L,41844L,41845L,41846L,41847L,41848L,41849L,41850L,41851L,41852L,
8389441853L,41854L,41855L,41856L,41857L,41858L,41859L,41860L,41861L,41862L,
8389541863L,41864L,41865L,41866L,41867L,41868L,41869L,41870L,41871L,41872L,
8389641873L,41874L,41875L,41876L,41877L,41878L,41879L,41880L,41881L,41882L,
8389741883L,41884L,41885L,41886L,41887L,41888L,41889L,41890L,41891L,41892L,
8389841893L,41894L,41895L,41896L,41897L,41898L,41899L,41900L,41901L,41902L,
8389941903L,41904L,41905L,41906L,41907L,41908L,41909L,41910L,41911L,41912L,
8390041913L,41914L,41915L,41916L,41917L,41918L,41919L,41920L,41921L,41922L,
8390141923L,41924L,41925L,41926L,41927L,41928L,41929L,41930L,41931L,41932L,
8390241933L,41934L,41935L,41936L,41937L,41938L,41939L,41940L,41941L,41942L,
8390341943L,41944L,41945L,41946L,41947L,41948L,41949L,41950L,41951L,41952L,
8390441953L,41954L,41955L,41956L,41957L,41958L,41959L,41960L,41961L,41962L,
8390541963L,41964L,41965L,41966L,41967L,41968L,41969L,41970L,41971L,41972L,
8390641973L,41974L,41975L,41976L,41977L,41978L,41979L,41980L,41981L,41982L,
8390741983L,41984L,41985L,41986L,41987L,41988L,41989L,41990L,41991L,41992L,
8390841993L,41994L,41995L,41996L,41997L,41998L,41999L,42000L,42001L,42002L,
8390942003L,42004L,42005L,42006L,42007L,42008L,42009L,42010L,42011L,42012L,
8391042013L,42014L,42015L,42016L,42017L,42018L,42019L,42020L,42021L,42022L,
8391142023L,42024L,42025L,42026L,42027L,42028L,42029L,42030L,42031L,42032L,
8391242033L,42034L,42035L,42036L,42037L,42038L,42039L,42040L,42041L,42042L,
8391342043L,42044L,42045L,42046L,42047L,42048L,42049L,42050L,42051L,42052L,
8391442053L,42054L,42055L,42056L,42057L,42058L,42059L,42060L,42061L,42062L,
8391542063L,42064L,42065L,42066L,42067L,42068L,42069L,42070L,42071L,42072L,
8391642073L,42074L,42075L,42076L,42077L,42078L,42079L,42080L,42081L,42082L,
8391742083L,42084L,42085L,42086L,42087L,42088L,42089L,42090L,42091L,42092L,
8391842093L,42094L,42095L,42096L,42097L,42098L,42099L,42100L,42101L,42102L,
8391942103L,42104L,42105L,42106L,42107L,42108L,42109L,42110L,42111L,42112L,
8392042113L,42114L,42115L,42116L,42117L,42118L,42119L,42120L,42121L,42122L,
8392142123L,42124L,42125L,42126L,42127L,42128L,42129L,42130L,42131L,42132L,
8392242133L,42134L,42135L,42136L,42137L,42138L,42139L,42140L,42141L,42142L,
8392342143L,42144L,42145L,42146L,42147L,42148L,42149L,42150L,42151L,42152L,
8392442153L,42154L,42155L,42156L,42157L,42158L,42159L,42160L,42161L,42162L,
8392542163L,42164L,42165L,42166L,42167L,42168L,42169L,42170L,42171L,42172L,
8392642173L,42174L,42175L,42176L,42177L,42178L,42179L,42180L,42181L,42182L,
8392742183L,42184L,42185L,42186L,42187L,42188L,42189L,42190L,42191L,42192L,
8392842193L,42194L,42195L,42196L,42197L,42198L,42199L,42200L,42201L,42202L,
8392942203L,42204L,42205L,42206L,42207L,42208L,42209L,42210L,42211L,42212L,
8393042213L,42214L,42215L,42216L,42217L,42218L,42219L,42220L,42221L,42222L,
8393142223L,42224L,42225L,42226L,42227L,42228L,42229L,42230L,42231L,42232L,
8393242233L,42234L,42235L,42236L,42237L,42238L,42239L,42240L,42241L,42242L,
8393342243L,42244L,42245L,42246L,42247L,42248L,42249L,42250L,42251L,42252L,
8393442253L,42254L,42255L,42256L,42257L,42258L,42259L,42260L,42261L,42262L,
8393542263L,42264L,42265L,42266L,42267L,42268L,42269L,42270L,42271L,42272L,
8393642273L,42274L,42275L,42276L,42277L,42278L,42279L,42280L,42281L,42282L,
8393742283L,42284L,42285L,42286L,42287L,42288L,42289L,42290L,42291L,42292L,
8393842293L,42294L,42295L,42296L,42297L,42298L,42299L,42300L,42301L,42302L,
8393942303L,42304L,42305L,42306L,42307L,42308L,42309L,42310L,42311L,42312L,
8394042313L,42314L,42315L,42316L,42317L,42318L,42319L,42320L,42321L,42322L,
8394142323L,42324L,42325L,42326L,42327L,42328L,42329L,42330L,42331L,42332L,
8394242333L,42334L,42335L,42336L,42337L,42338L,42339L,42340L,42341L,42342L,
8394342343L,42344L,42345L,42346L,42347L,42348L,42349L,42350L,42351L,42352L,
8394442353L,42354L,42355L,42356L,42357L,42358L,42359L,42360L,42361L,42362L,
8394542363L,42364L,42365L,42366L,42367L,42368L,42369L,42370L,42371L,42372L,
8394642373L,42374L,42375L,42376L,42377L,42378L,42379L,42380L,42381L,42382L,
8394742383L,42384L,42385L,42386L,42387L,42388L,42389L,42390L,42391L,42392L,
8394842393L,42394L,42395L,42396L,42397L,42398L,42399L,42400L,42401L,42402L,
8394942403L,42404L,42405L,42406L,42407L,42408L,42409L,42410L,42411L,42412L,
8395042413L,42414L,42415L,42416L,42417L,42418L,42419L,42420L,42421L,42422L,
8395142423L,42424L,42425L,42426L,42427L,42428L,42429L,42430L,42431L,42432L,
8395242433L,42434L,42435L,42436L,42437L,42438L,42439L,42440L,42441L,42442L,
8395342443L,42444L,42445L,42446L,42447L,42448L,42449L,42450L,42451L,42452L,
8395442453L,42454L,42455L,42456L,42457L,42458L,42459L,42460L,42461L,42462L,
8395542463L,42464L,42465L,42466L,42467L,42468L,42469L,42470L,42471L,42472L,
8395642473L,42474L,42475L,42476L,42477L,42478L,42479L,42480L,42481L,42482L,
8395742483L,42484L,42485L,42486L,42487L,42488L,42489L,42490L,42491L,42492L,
8395842493L,42494L,42495L,42496L,42497L,42498L,42499L,42500L,42501L,42502L,
8395942503L,42504L,42505L,42506L,42507L,42508L,42509L,42510L,42511L,42512L,
8396042513L,42514L,42515L,42516L,42517L,42518L,42519L,42520L,42521L,42522L,
8396142523L,42524L,42525L,42526L,42527L,42528L,42529L,42530L,42531L,42532L,
8396242533L,42534L,42535L,42536L,42537L,42538L,42539L,42540L,42541L,42542L,
8396342543L,42544L,42545L,42546L,42547L,42548L,42549L,42550L,42551L,42552L,
8396442553L,42554L,42555L,42556L,42557L,42558L,42559L,42560L,42560L,42562L,
8396542562L,42564L,42564L,42566L,42566L,42568L,42568L,42570L,42570L,42572L,
8396642572L,42574L,42574L,42576L,42576L,42578L,42578L,42580L,42580L,42582L,
8396742582L,42584L,42584L,42586L,42586L,42588L,42588L,42590L,42590L,42592L,
8396842592L,42594L,42594L,42596L,42596L,42598L,42598L,42600L,42600L,42602L,
8396942602L,42604L,42604L,42606L,42607L,42608L,42609L,42610L,42611L,42612L,
8397042613L,42614L,42615L,42616L,42617L,42618L,42619L,42620L,42621L,42622L,
8397142623L,42624L,42624L,42626L,42626L,42628L,42628L,42630L,42630L,42632L,
8397242632L,42634L,42634L,42636L,42636L,42638L,42638L,42640L,42640L,42642L,
8397342642L,42644L,42644L,42646L,42646L,42648L,42649L,42650L,42651L,42652L,
8397442653L,42654L,42655L,42656L,42657L,42658L,42659L,42660L,42661L,42662L,
8397542663L,42664L,42665L,42666L,42667L,42668L,42669L,42670L,42671L,42672L,
8397642673L,42674L,42675L,42676L,42677L,42678L,42679L,42680L,42681L,42682L,
8397742683L,42684L,42685L,42686L,42687L,42688L,42689L,42690L,42691L,42692L,
8397842693L,42694L,42695L,42696L,42697L,42698L,42699L,42700L,42701L,42702L,
8397942703L,42704L,42705L,42706L,42707L,42708L,42709L,42710L,42711L,42712L,
8398042713L,42714L,42715L,42716L,42717L,42718L,42719L,42720L,42721L,42722L,
8398142723L,42724L,42725L,42726L,42727L,42728L,42729L,42730L,42731L,42732L,
8398242733L,42734L,42735L,42736L,42737L,42738L,42739L,42740L,42741L,42742L,
8398342743L,42744L,42745L,42746L,42747L,42748L,42749L,42750L,42751L,42752L,
8398442753L,42754L,42755L,42756L,42757L,42758L,42759L,42760L,42761L,42762L,
8398542763L,42764L,42765L,42766L,42767L,42768L,42769L,42770L,42771L,42772L,
8398642773L,42774L,42775L,42776L,42777L,42778L,42779L,42780L,42781L,42782L,
8398742783L,42784L,42785L,42786L,42786L,42788L,42788L,42790L,42790L,42792L,
8398842792L,42794L,42794L,42796L,42796L,42798L,42798L,42800L,42801L,42802L,
8398942802L,42804L,42804L,42806L,42806L,42808L,42808L,42810L,42810L,42812L,
8399042812L,42814L,42814L,42816L,42816L,42818L,42818L,42820L,42820L,42822L,
8399142822L,42824L,42824L,42826L,42826L,42828L,42828L,42830L,42830L,42832L,
8399242832L,42834L,42834L,42836L,42836L,42838L,42838L,42840L,42840L,42842L,
8399342842L,42844L,42844L,42846L,42846L,42848L,42848L,42850L,42850L,42852L,
8399442852L,42854L,42854L,42856L,42856L,42858L,42858L,42860L,42860L,42862L,
8399542862L,42864L,42865L,42866L,42867L,42868L,42869L,42870L,42871L,42872L,
8399642873L,42873L,42875L,42875L,42877L,42878L,42878L,42880L,42880L,42882L,
8399742882L,42884L,42884L,42886L,42886L,42888L,42889L,42890L,42891L,42891L,
8399842893L,42894L,42895L,42896L,42896L,42898L,42899L,42900L,42901L,42902L,
8399942903L,42904L,42905L,42906L,42907L,42908L,42909L,42910L,42911L,42912L,
8400042912L,42914L,42914L,42916L,42916L,42918L,42918L,42920L,42920L,42922L,
8400142923L,42924L,42925L,42926L,42927L,42928L,42929L,42930L,42931L,42932L,
8400242933L,42934L,42935L,42936L,42937L,42938L,42939L,42940L,42941L,42942L,
8400342943L,42944L,42945L,42946L,42947L,42948L,42949L,42950L,42951L,42952L,
8400442953L,42954L,42955L,42956L,42957L,42958L,42959L,42960L,42961L,42962L,
8400542963L,42964L,42965L,42966L,42967L,42968L,42969L,42970L,42971L,42972L,
8400642973L,42974L,42975L,42976L,42977L,42978L,42979L,42980L,42981L,42982L,
8400742983L,42984L,42985L,42986L,42987L,42988L,42989L,42990L,42991L,42992L,
8400842993L,42994L,42995L,42996L,42997L,42998L,42999L,43000L,43001L,43002L,
8400943003L,43004L,43005L,43006L,43007L,43008L,43009L,43010L,43011L,43012L,
8401043013L,43014L,43015L,43016L,43017L,43018L,43019L,43020L,43021L,43022L,
8401143023L,43024L,43025L,43026L,43027L,43028L,43029L,43030L,43031L,43032L,
8401243033L,43034L,43035L,43036L,43037L,43038L,43039L,43040L,43041L,43042L,
8401343043L,43044L,43045L,43046L,43047L,43048L,43049L,43050L,43051L,43052L,
8401443053L,43054L,43055L,43056L,43057L,43058L,43059L,43060L,43061L,43062L,
8401543063L,43064L,43065L,43066L,43067L,43068L,43069L,43070L,43071L,43072L,
8401643073L,43074L,43075L,43076L,43077L,43078L,43079L,43080L,43081L,43082L,
8401743083L,43084L,43085L,43086L,43087L,43088L,43089L,43090L,43091L,43092L,
8401843093L,43094L,43095L,43096L,43097L,43098L,43099L,43100L,43101L,43102L,
8401943103L,43104L,43105L,43106L,43107L,43108L,43109L,43110L,43111L,43112L,
8402043113L,43114L,43115L,43116L,43117L,43118L,43119L,43120L,43121L,43122L,
8402143123L,43124L,43125L,43126L,43127L,43128L,43129L,43130L,43131L,43132L,
8402243133L,43134L,43135L,43136L,43137L,43138L,43139L,43140L,43141L,43142L,
8402343143L,43144L,43145L,43146L,43147L,43148L,43149L,43150L,43151L,43152L,
8402443153L,43154L,43155L,43156L,43157L,43158L,43159L,43160L,43161L,43162L,
8402543163L,43164L,43165L,43166L,43167L,43168L,43169L,43170L,43171L,43172L,
8402643173L,43174L,43175L,43176L,43177L,43178L,43179L,43180L,43181L,43182L,
8402743183L,43184L,43185L,43186L,43187L,43188L,43189L,43190L,43191L,43192L,
8402843193L,43194L,43195L,43196L,43197L,43198L,43199L,43200L,43201L,43202L,
8402943203L,43204L,43205L,43206L,43207L,43208L,43209L,43210L,43211L,43212L,
8403043213L,43214L,43215L,43216L,43217L,43218L,43219L,43220L,43221L,43222L,
8403143223L,43224L,43225L,43226L,43227L,43228L,43229L,43230L,43231L,43232L,
8403243233L,43234L,43235L,43236L,43237L,43238L,43239L,43240L,43241L,43242L,
8403343243L,43244L,43245L,43246L,43247L,43248L,43249L,43250L,43251L,43252L,
8403443253L,43254L,43255L,43256L,43257L,43258L,43259L,43260L,43261L,43262L,
8403543263L,43264L,43265L,43266L,43267L,43268L,43269L,43270L,43271L,43272L,
8403643273L,43274L,43275L,43276L,43277L,43278L,43279L,43280L,43281L,43282L,
8403743283L,43284L,43285L,43286L,43287L,43288L,43289L,43290L,43291L,43292L,
8403843293L,43294L,43295L,43296L,43297L,43298L,43299L,43300L,43301L,43302L,
8403943303L,43304L,43305L,43306L,43307L,43308L,43309L,43310L,43311L,43312L,
8404043313L,43314L,43315L,43316L,43317L,43318L,43319L,43320L,43321L,43322L,
8404143323L,43324L,43325L,43326L,43327L,43328L,43329L,43330L,43331L,43332L,
8404243333L,43334L,43335L,43336L,43337L,43338L,43339L,43340L,43341L,43342L,
8404343343L,43344L,43345L,43346L,43347L,43348L,43349L,43350L,43351L,43352L,
8404443353L,43354L,43355L,43356L,43357L,43358L,43359L,43360L,43361L,43362L,
8404543363L,43364L,43365L,43366L,43367L,43368L,43369L,43370L,43371L,43372L,
8404643373L,43374L,43375L,43376L,43377L,43378L,43379L,43380L,43381L,43382L,
8404743383L,43384L,43385L,43386L,43387L,43388L,43389L,43390L,43391L,43392L,
8404843393L,43394L,43395L,43396L,43397L,43398L,43399L,43400L,43401L,43402L,
8404943403L,43404L,43405L,43406L,43407L,43408L,43409L,43410L,43411L,43412L,
8405043413L,43414L,43415L,43416L,43417L,43418L,43419L,43420L,43421L,43422L,
8405143423L,43424L,43425L,43426L,43427L,43428L,43429L,43430L,43431L,43432L,
8405243433L,43434L,43435L,43436L,43437L,43438L,43439L,43440L,43441L,43442L,
8405343443L,43444L,43445L,43446L,43447L,43448L,43449L,43450L,43451L,43452L,
8405443453L,43454L,43455L,43456L,43457L,43458L,43459L,43460L,43461L,43462L,
8405543463L,43464L,43465L,43466L,43467L,43468L,43469L,43470L,43471L,43472L,
8405643473L,43474L,43475L,43476L,43477L,43478L,43479L,43480L,43481L,43482L,
8405743483L,43484L,43485L,43486L,43487L,43488L,43489L,43490L,43491L,43492L,
8405843493L,43494L,43495L,43496L,43497L,43498L,43499L,43500L,43501L,43502L,
8405943503L,43504L,43505L,43506L,43507L,43508L,43509L,43510L,43511L,43512L,
8406043513L,43514L,43515L,43516L,43517L,43518L,43519L,43520L,43521L,43522L,
8406143523L,43524L,43525L,43526L,43527L,43528L,43529L,43530L,43531L,43532L,
8406243533L,43534L,43535L,43536L,43537L,43538L,43539L,43540L,43541L,43542L,
8406343543L,43544L,43545L,43546L,43547L,43548L,43549L,43550L,43551L,43552L,
8406443553L,43554L,43555L,43556L,43557L,43558L,43559L,43560L,43561L,43562L,
8406543563L,43564L,43565L,43566L,43567L,43568L,43569L,43570L,43571L,43572L,
8406643573L,43574L,43575L,43576L,43577L,43578L,43579L,43580L,43581L,43582L,
8406743583L,43584L,43585L,43586L,43587L,43588L,43589L,43590L,43591L,43592L,
8406843593L,43594L,43595L,43596L,43597L,43598L,43599L,43600L,43601L,43602L,
8406943603L,43604L,43605L,43606L,43607L,43608L,43609L,43610L,43611L,43612L,
8407043613L,43614L,43615L,43616L,43617L,43618L,43619L,43620L,43621L,43622L,
8407143623L,43624L,43625L,43626L,43627L,43628L,43629L,43630L,43631L,43632L,
8407243633L,43634L,43635L,43636L,43637L,43638L,43639L,43640L,43641L,43642L,
8407343643L,43644L,43645L,43646L,43647L,43648L,43649L,43650L,43651L,43652L,
8407443653L,43654L,43655L,43656L,43657L,43658L,43659L,43660L,43661L,43662L,
8407543663L,43664L,43665L,43666L,43667L,43668L,43669L,43670L,43671L,43672L,
8407643673L,43674L,43675L,43676L,43677L,43678L,43679L,43680L,43681L,43682L,
8407743683L,43684L,43685L,43686L,43687L,43688L,43689L,43690L,43691L,43692L,
8407843693L,43694L,43695L,43696L,43697L,43698L,43699L,43700L,43701L,43702L,
8407943703L,43704L,43705L,43706L,43707L,43708L,43709L,43710L,43711L,43712L,
8408043713L,43714L,43715L,43716L,43717L,43718L,43719L,43720L,43721L,43722L,
8408143723L,43724L,43725L,43726L,43727L,43728L,43729L,43730L,43731L,43732L,
8408243733L,43734L,43735L,43736L,43737L,43738L,43739L,43740L,43741L,43742L,
8408343743L,43744L,43745L,43746L,43747L,43748L,43749L,43750L,43751L,43752L,
8408443753L,43754L,43755L,43756L,43757L,43758L,43759L,43760L,43761L,43762L,
8408543763L,43764L,43765L,43766L,43767L,43768L,43769L,43770L,43771L,43772L,
8408643773L,43774L,43775L,43776L,43777L,43778L,43779L,43780L,43781L,43782L,
8408743783L,43784L,43785L,43786L,43787L,43788L,43789L,43790L,43791L,43792L,
8408843793L,43794L,43795L,43796L,43797L,43798L,43799L,43800L,43801L,43802L,
8408943803L,43804L,43805L,43806L,43807L,43808L,43809L,43810L,43811L,43812L,
8409043813L,43814L,43815L,43816L,43817L,43818L,43819L,43820L,43821L,43822L,
8409143823L,43824L,43825L,43826L,43827L,43828L,43829L,43830L,43831L,43832L,
8409243833L,43834L,43835L,43836L,43837L,43838L,43839L,43840L,43841L,43842L,
8409343843L,43844L,43845L,43846L,43847L,43848L,43849L,43850L,43851L,43852L,
8409443853L,43854L,43855L,43856L,43857L,43858L,43859L,43860L,43861L,43862L,
8409543863L,43864L,43865L,43866L,43867L,43868L,43869L,43870L,43871L,43872L,
8409643873L,43874L,43875L,43876L,43877L,43878L,43879L,43880L,43881L,43882L,
8409743883L,43884L,43885L,43886L,43887L,43888L,43889L,43890L,43891L,43892L,
8409843893L,43894L,43895L,43896L,43897L,43898L,43899L,43900L,43901L,43902L,
8409943903L,43904L,43905L,43906L,43907L,43908L,43909L,43910L,43911L,43912L,
8410043913L,43914L,43915L,43916L,43917L,43918L,43919L,43920L,43921L,43922L,
8410143923L,43924L,43925L,43926L,43927L,43928L,43929L,43930L,43931L,43932L,
8410243933L,43934L,43935L,43936L,43937L,43938L,43939L,43940L,43941L,43942L,
8410343943L,43944L,43945L,43946L,43947L,43948L,43949L,43950L,43951L,43952L,
8410443953L,43954L,43955L,43956L,43957L,43958L,43959L,43960L,43961L,43962L,
8410543963L,43964L,43965L,43966L,43967L,43968L,43969L,43970L,43971L,43972L,
8410643973L,43974L,43975L,43976L,43977L,43978L,43979L,43980L,43981L,43982L,
8410743983L,43984L,43985L,43986L,43987L,43988L,43989L,43990L,43991L,43992L,
8410843993L,43994L,43995L,43996L,43997L,43998L,43999L,44000L,44001L,44002L,
8410944003L,44004L,44005L,44006L,44007L,44008L,44009L,44010L,44011L,44012L,
8411044013L,44014L,44015L,44016L,44017L,44018L,44019L,44020L,44021L,44022L,
8411144023L,44024L,44025L,44026L,44027L,44028L,44029L,44030L,44031L,44032L,
8411244033L,44034L,44035L,44036L,44037L,44038L,44039L,44040L,44041L,44042L,
8411344043L,44044L,44045L,44046L,44047L,44048L,44049L,44050L,44051L,44052L,
8411444053L,44054L,44055L,44056L,44057L,44058L,44059L,44060L,44061L,44062L,
8411544063L,44064L,44065L,44066L,44067L,44068L,44069L,44070L,44071L,44072L,
8411644073L,44074L,44075L,44076L,44077L,44078L,44079L,44080L,44081L,44082L,
8411744083L,44084L,44085L,44086L,44087L,44088L,44089L,44090L,44091L,44092L,
8411844093L,44094L,44095L,44096L,44097L,44098L,44099L,44100L,44101L,44102L,
8411944103L,44104L,44105L,44106L,44107L,44108L,44109L,44110L,44111L,44112L,
8412044113L,44114L,44115L,44116L,44117L,44118L,44119L,44120L,44121L,44122L,
8412144123L,44124L,44125L,44126L,44127L,44128L,44129L,44130L,44131L,44132L,
8412244133L,44134L,44135L,44136L,44137L,44138L,44139L,44140L,44141L,44142L,
8412344143L,44144L,44145L,44146L,44147L,44148L,44149L,44150L,44151L,44152L,
8412444153L,44154L,44155L,44156L,44157L,44158L,44159L,44160L,44161L,44162L,
8412544163L,44164L,44165L,44166L,44167L,44168L,44169L,44170L,44171L,44172L,
8412644173L,44174L,44175L,44176L,44177L,44178L,44179L,44180L,44181L,44182L,
8412744183L,44184L,44185L,44186L,44187L,44188L,44189L,44190L,44191L,44192L,
8412844193L,44194L,44195L,44196L,44197L,44198L,44199L,44200L,44201L,44202L,
8412944203L,44204L,44205L,44206L,44207L,44208L,44209L,44210L,44211L,44212L,
8413044213L,44214L,44215L,44216L,44217L,44218L,44219L,44220L,44221L,44222L,
8413144223L,44224L,44225L,44226L,44227L,44228L,44229L,44230L,44231L,44232L,
8413244233L,44234L,44235L,44236L,44237L,44238L,44239L,44240L,44241L,44242L,
8413344243L,44244L,44245L,44246L,44247L,44248L,44249L,44250L,44251L,44252L,
8413444253L,44254L,44255L,44256L,44257L,44258L,44259L,44260L,44261L,44262L,
8413544263L,44264L,44265L,44266L,44267L,44268L,44269L,44270L,44271L,44272L,
8413644273L,44274L,44275L,44276L,44277L,44278L,44279L,44280L,44281L,44282L,
8413744283L,44284L,44285L,44286L,44287L,44288L,44289L,44290L,44291L,44292L,
8413844293L,44294L,44295L,44296L,44297L,44298L,44299L,44300L,44301L,44302L,
8413944303L,44304L,44305L,44306L,44307L,44308L,44309L,44310L,44311L,44312L,
8414044313L,44314L,44315L,44316L,44317L,44318L,44319L,44320L,44321L,44322L,
8414144323L,44324L,44325L,44326L,44327L,44328L,44329L,44330L,44331L,44332L,
8414244333L,44334L,44335L,44336L,44337L,44338L,44339L,44340L,44341L,44342L,
8414344343L,44344L,44345L,44346L,44347L,44348L,44349L,44350L,44351L,44352L,
8414444353L,44354L,44355L,44356L,44357L,44358L,44359L,44360L,44361L,44362L,
8414544363L,44364L,44365L,44366L,44367L,44368L,44369L,44370L,44371L,44372L,
8414644373L,44374L,44375L,44376L,44377L,44378L,44379L,44380L,44381L,44382L,
8414744383L,44384L,44385L,44386L,44387L,44388L,44389L,44390L,44391L,44392L,
8414844393L,44394L,44395L,44396L,44397L,44398L,44399L,44400L,44401L,44402L,
8414944403L,44404L,44405L,44406L,44407L,44408L,44409L,44410L,44411L,44412L,
8415044413L,44414L,44415L,44416L,44417L,44418L,44419L,44420L,44421L,44422L,
8415144423L,44424L,44425L,44426L,44427L,44428L,44429L,44430L,44431L,44432L,
8415244433L,44434L,44435L,44436L,44437L,44438L,44439L,44440L,44441L,44442L,
8415344443L,44444L,44445L,44446L,44447L,44448L,44449L,44450L,44451L,44452L,
8415444453L,44454L,44455L,44456L,44457L,44458L,44459L,44460L,44461L,44462L,
8415544463L,44464L,44465L,44466L,44467L,44468L,44469L,44470L,44471L,44472L,
8415644473L,44474L,44475L,44476L,44477L,44478L,44479L,44480L,44481L,44482L,
8415744483L,44484L,44485L,44486L,44487L,44488L,44489L,44490L,44491L,44492L,
8415844493L,44494L,44495L,44496L,44497L,44498L,44499L,44500L,44501L,44502L,
8415944503L,44504L,44505L,44506L,44507L,44508L,44509L,44510L,44511L,44512L,
8416044513L,44514L,44515L,44516L,44517L,44518L,44519L,44520L,44521L,44522L,
8416144523L,44524L,44525L,44526L,44527L,44528L,44529L,44530L,44531L,44532L,
8416244533L,44534L,44535L,44536L,44537L,44538L,44539L,44540L,44541L,44542L,
8416344543L,44544L,44545L,44546L,44547L,44548L,44549L,44550L,44551L,44552L,
8416444553L,44554L,44555L,44556L,44557L,44558L,44559L,44560L,44561L,44562L,
8416544563L,44564L,44565L,44566L,44567L,44568L,44569L,44570L,44571L,44572L,
8416644573L,44574L,44575L,44576L,44577L,44578L,44579L,44580L,44581L,44582L,
8416744583L,44584L,44585L,44586L,44587L,44588L,44589L,44590L,44591L,44592L,
8416844593L,44594L,44595L,44596L,44597L,44598L,44599L,44600L,44601L,44602L,
8416944603L,44604L,44605L,44606L,44607L,44608L,44609L,44610L,44611L,44612L,
8417044613L,44614L,44615L,44616L,44617L,44618L,44619L,44620L,44621L,44622L,
8417144623L,44624L,44625L,44626L,44627L,44628L,44629L,44630L,44631L,44632L,
8417244633L,44634L,44635L,44636L,44637L,44638L,44639L,44640L,44641L,44642L,
8417344643L,44644L,44645L,44646L,44647L,44648L,44649L,44650L,44651L,44652L,
8417444653L,44654L,44655L,44656L,44657L,44658L,44659L,44660L,44661L,44662L,
8417544663L,44664L,44665L,44666L,44667L,44668L,44669L,44670L,44671L,44672L,
8417644673L,44674L,44675L,44676L,44677L,44678L,44679L,44680L,44681L,44682L,
8417744683L,44684L,44685L,44686L,44687L,44688L,44689L,44690L,44691L,44692L,
8417844693L,44694L,44695L,44696L,44697L,44698L,44699L,44700L,44701L,44702L,
8417944703L,44704L,44705L,44706L,44707L,44708L,44709L,44710L,44711L,44712L,
8418044713L,44714L,44715L,44716L,44717L,44718L,44719L,44720L,44721L,44722L,
8418144723L,44724L,44725L,44726L,44727L,44728L,44729L,44730L,44731L,44732L,
8418244733L,44734L,44735L,44736L,44737L,44738L,44739L,44740L,44741L,44742L,
8418344743L,44744L,44745L,44746L,44747L,44748L,44749L,44750L,44751L,44752L,
8418444753L,44754L,44755L,44756L,44757L,44758L,44759L,44760L,44761L,44762L,
8418544763L,44764L,44765L,44766L,44767L,44768L,44769L,44770L,44771L,44772L,
8418644773L,44774L,44775L,44776L,44777L,44778L,44779L,44780L,44781L,44782L,
8418744783L,44784L,44785L,44786L,44787L,44788L,44789L,44790L,44791L,44792L,
8418844793L,44794L,44795L,44796L,44797L,44798L,44799L,44800L,44801L,44802L,
8418944803L,44804L,44805L,44806L,44807L,44808L,44809L,44810L,44811L,44812L,
8419044813L,44814L,44815L,44816L,44817L,44818L,44819L,44820L,44821L,44822L,
8419144823L,44824L,44825L,44826L,44827L,44828L,44829L,44830L,44831L,44832L,
8419244833L,44834L,44835L,44836L,44837L,44838L,44839L,44840L,44841L,44842L,
8419344843L,44844L,44845L,44846L,44847L,44848L,44849L,44850L,44851L,44852L,
8419444853L,44854L,44855L,44856L,44857L,44858L,44859L,44860L,44861L,44862L,
8419544863L,44864L,44865L,44866L,44867L,44868L,44869L,44870L,44871L,44872L,
8419644873L,44874L,44875L,44876L,44877L,44878L,44879L,44880L,44881L,44882L,
8419744883L,44884L,44885L,44886L,44887L,44888L,44889L,44890L,44891L,44892L,
8419844893L,44894L,44895L,44896L,44897L,44898L,44899L,44900L,44901L,44902L,
8419944903L,44904L,44905L,44906L,44907L,44908L,44909L,44910L,44911L,44912L,
8420044913L,44914L,44915L,44916L,44917L,44918L,44919L,44920L,44921L,44922L,
8420144923L,44924L,44925L,44926L,44927L,44928L,44929L,44930L,44931L,44932L,
8420244933L,44934L,44935L,44936L,44937L,44938L,44939L,44940L,44941L,44942L,
8420344943L,44944L,44945L,44946L,44947L,44948L,44949L,44950L,44951L,44952L,
8420444953L,44954L,44955L,44956L,44957L,44958L,44959L,44960L,44961L,44962L,
8420544963L,44964L,44965L,44966L,44967L,44968L,44969L,44970L,44971L,44972L,
8420644973L,44974L,44975L,44976L,44977L,44978L,44979L,44980L,44981L,44982L,
8420744983L,44984L,44985L,44986L,44987L,44988L,44989L,44990L,44991L,44992L,
8420844993L,44994L,44995L,44996L,44997L,44998L,44999L,45000L,45001L,45002L,
8420945003L,45004L,45005L,45006L,45007L,45008L,45009L,45010L,45011L,45012L,
8421045013L,45014L,45015L,45016L,45017L,45018L,45019L,45020L,45021L,45022L,
8421145023L,45024L,45025L,45026L,45027L,45028L,45029L,45030L,45031L,45032L,
8421245033L,45034L,45035L,45036L,45037L,45038L,45039L,45040L,45041L,45042L,
8421345043L,45044L,45045L,45046L,45047L,45048L,45049L,45050L,45051L,45052L,
8421445053L,45054L,45055L,45056L,45057L,45058L,45059L,45060L,45061L,45062L,
8421545063L,45064L,45065L,45066L,45067L,45068L,45069L,45070L,45071L,45072L,
8421645073L,45074L,45075L,45076L,45077L,45078L,45079L,45080L,45081L,45082L,
8421745083L,45084L,45085L,45086L,45087L,45088L,45089L,45090L,45091L,45092L,
8421845093L,45094L,45095L,45096L,45097L,45098L,45099L,45100L,45101L,45102L,
8421945103L,45104L,45105L,45106L,45107L,45108L,45109L,45110L,45111L,45112L,
8422045113L,45114L,45115L,45116L,45117L,45118L,45119L,45120L,45121L,45122L,
8422145123L,45124L,45125L,45126L,45127L,45128L,45129L,45130L,45131L,45132L,
8422245133L,45134L,45135L,45136L,45137L,45138L,45139L,45140L,45141L,45142L,
8422345143L,45144L,45145L,45146L,45147L,45148L,45149L,45150L,45151L,45152L,
8422445153L,45154L,45155L,45156L,45157L,45158L,45159L,45160L,45161L,45162L,
8422545163L,45164L,45165L,45166L,45167L,45168L,45169L,45170L,45171L,45172L,
8422645173L,45174L,45175L,45176L,45177L,45178L,45179L,45180L,45181L,45182L,
8422745183L,45184L,45185L,45186L,45187L,45188L,45189L,45190L,45191L,45192L,
8422845193L,45194L,45195L,45196L,45197L,45198L,45199L,45200L,45201L,45202L,
8422945203L,45204L,45205L,45206L,45207L,45208L,45209L,45210L,45211L,45212L,
8423045213L,45214L,45215L,45216L,45217L,45218L,45219L,45220L,45221L,45222L,
8423145223L,45224L,45225L,45226L,45227L,45228L,45229L,45230L,45231L,45232L,
8423245233L,45234L,45235L,45236L,45237L,45238L,45239L,45240L,45241L,45242L,
8423345243L,45244L,45245L,45246L,45247L,45248L,45249L,45250L,45251L,45252L,
8423445253L,45254L,45255L,45256L,45257L,45258L,45259L,45260L,45261L,45262L,
8423545263L,45264L,45265L,45266L,45267L,45268L,45269L,45270L,45271L,45272L,
8423645273L,45274L,45275L,45276L,45277L,45278L,45279L,45280L,45281L,45282L,
8423745283L,45284L,45285L,45286L,45287L,45288L,45289L,45290L,45291L,45292L,
8423845293L,45294L,45295L,45296L,45297L,45298L,45299L,45300L,45301L,45302L,
8423945303L,45304L,45305L,45306L,45307L,45308L,45309L,45310L,45311L,45312L,
8424045313L,45314L,45315L,45316L,45317L,45318L,45319L,45320L,45321L,45322L,
8424145323L,45324L,45325L,45326L,45327L,45328L,45329L,45330L,45331L,45332L,
8424245333L,45334L,45335L,45336L,45337L,45338L,45339L,45340L,45341L,45342L,
8424345343L,45344L,45345L,45346L,45347L,45348L,45349L,45350L,45351L,45352L,
8424445353L,45354L,45355L,45356L,45357L,45358L,45359L,45360L,45361L,45362L,
8424545363L,45364L,45365L,45366L,45367L,45368L,45369L,45370L,45371L,45372L,
8424645373L,45374L,45375L,45376L,45377L,45378L,45379L,45380L,45381L,45382L,
8424745383L,45384L,45385L,45386L,45387L,45388L,45389L,45390L,45391L,45392L,
8424845393L,45394L,45395L,45396L,45397L,45398L,45399L,45400L,45401L,45402L,
8424945403L,45404L,45405L,45406L,45407L,45408L,45409L,45410L,45411L,45412L,
8425045413L,45414L,45415L,45416L,45417L,45418L,45419L,45420L,45421L,45422L,
8425145423L,45424L,45425L,45426L,45427L,45428L,45429L,45430L,45431L,45432L,
8425245433L,45434L,45435L,45436L,45437L,45438L,45439L,45440L,45441L,45442L,
8425345443L,45444L,45445L,45446L,45447L,45448L,45449L,45450L,45451L,45452L,
8425445453L,45454L,45455L,45456L,45457L,45458L,45459L,45460L,45461L,45462L,
8425545463L,45464L,45465L,45466L,45467L,45468L,45469L,45470L,45471L,45472L,
8425645473L,45474L,45475L,45476L,45477L,45478L,45479L,45480L,45481L,45482L,
8425745483L,45484L,45485L,45486L,45487L,45488L,45489L,45490L,45491L,45492L,
8425845493L,45494L,45495L,45496L,45497L,45498L,45499L,45500L,45501L,45502L,
8425945503L,45504L,45505L,45506L,45507L,45508L,45509L,45510L,45511L,45512L,
8426045513L,45514L,45515L,45516L,45517L,45518L,45519L,45520L,45521L,45522L,
8426145523L,45524L,45525L,45526L,45527L,45528L,45529L,45530L,45531L,45532L,
8426245533L,45534L,45535L,45536L,45537L,45538L,45539L,45540L,45541L,45542L,
8426345543L,45544L,45545L,45546L,45547L,45548L,45549L,45550L,45551L,45552L,
8426445553L,45554L,45555L,45556L,45557L,45558L,45559L,45560L,45561L,45562L,
8426545563L,45564L,45565L,45566L,45567L,45568L,45569L,45570L,45571L,45572L,
8426645573L,45574L,45575L,45576L,45577L,45578L,45579L,45580L,45581L,45582L,
8426745583L,45584L,45585L,45586L,45587L,45588L,45589L,45590L,45591L,45592L,
8426845593L,45594L,45595L,45596L,45597L,45598L,45599L,45600L,45601L,45602L,
8426945603L,45604L,45605L,45606L,45607L,45608L,45609L,45610L,45611L,45612L,
8427045613L,45614L,45615L,45616L,45617L,45618L,45619L,45620L,45621L,45622L,
8427145623L,45624L,45625L,45626L,45627L,45628L,45629L,45630L,45631L,45632L,
8427245633L,45634L,45635L,45636L,45637L,45638L,45639L,45640L,45641L,45642L,
8427345643L,45644L,45645L,45646L,45647L,45648L,45649L,45650L,45651L,45652L,
8427445653L,45654L,45655L,45656L,45657L,45658L,45659L,45660L,45661L,45662L,
8427545663L,45664L,45665L,45666L,45667L,45668L,45669L,45670L,45671L,45672L,
8427645673L,45674L,45675L,45676L,45677L,45678L,45679L,45680L,45681L,45682L,
8427745683L,45684L,45685L,45686L,45687L,45688L,45689L,45690L,45691L,45692L,
8427845693L,45694L,45695L,45696L,45697L,45698L,45699L,45700L,45701L,45702L,
8427945703L,45704L,45705L,45706L,45707L,45708L,45709L,45710L,45711L,45712L,
8428045713L,45714L,45715L,45716L,45717L,45718L,45719L,45720L,45721L,45722L,
8428145723L,45724L,45725L,45726L,45727L,45728L,45729L,45730L,45731L,45732L,
8428245733L,45734L,45735L,45736L,45737L,45738L,45739L,45740L,45741L,45742L,
8428345743L,45744L,45745L,45746L,45747L,45748L,45749L,45750L,45751L,45752L,
8428445753L,45754L,45755L,45756L,45757L,45758L,45759L,45760L,45761L,45762L,
8428545763L,45764L,45765L,45766L,45767L,45768L,45769L,45770L,45771L,45772L,
8428645773L,45774L,45775L,45776L,45777L,45778L,45779L,45780L,45781L,45782L,
8428745783L,45784L,45785L,45786L,45787L,45788L,45789L,45790L,45791L,45792L,
8428845793L,45794L,45795L,45796L,45797L,45798L,45799L,45800L,45801L,45802L,
8428945803L,45804L,45805L,45806L,45807L,45808L,45809L,45810L,45811L,45812L,
8429045813L,45814L,45815L,45816L,45817L,45818L,45819L,45820L,45821L,45822L,
8429145823L,45824L,45825L,45826L,45827L,45828L,45829L,45830L,45831L,45832L,
8429245833L,45834L,45835L,45836L,45837L,45838L,45839L,45840L,45841L,45842L,
8429345843L,45844L,45845L,45846L,45847L,45848L,45849L,45850L,45851L,45852L,
8429445853L,45854L,45855L,45856L,45857L,45858L,45859L,45860L,45861L,45862L,
8429545863L,45864L,45865L,45866L,45867L,45868L,45869L,45870L,45871L,45872L,
8429645873L,45874L,45875L,45876L,45877L,45878L,45879L,45880L,45881L,45882L,
8429745883L,45884L,45885L,45886L,45887L,45888L,45889L,45890L,45891L,45892L,
8429845893L,45894L,45895L,45896L,45897L,45898L,45899L,45900L,45901L,45902L,
8429945903L,45904L,45905L,45906L,45907L,45908L,45909L,45910L,45911L,45912L,
8430045913L,45914L,45915L,45916L,45917L,45918L,45919L,45920L,45921L,45922L,
8430145923L,45924L,45925L,45926L,45927L,45928L,45929L,45930L,45931L,45932L,
8430245933L,45934L,45935L,45936L,45937L,45938L,45939L,45940L,45941L,45942L,
8430345943L,45944L,45945L,45946L,45947L,45948L,45949L,45950L,45951L,45952L,
8430445953L,45954L,45955L,45956L,45957L,45958L,45959L,45960L,45961L,45962L,
8430545963L,45964L,45965L,45966L,45967L,45968L,45969L,45970L,45971L,45972L,
8430645973L,45974L,45975L,45976L,45977L,45978L,45979L,45980L,45981L,45982L,
8430745983L,45984L,45985L,45986L,45987L,45988L,45989L,45990L,45991L,45992L,
8430845993L,45994L,45995L,45996L,45997L,45998L,45999L,46000L,46001L,46002L,
8430946003L,46004L,46005L,46006L,46007L,46008L,46009L,46010L,46011L,46012L,
8431046013L,46014L,46015L,46016L,46017L,46018L,46019L,46020L,46021L,46022L,
8431146023L,46024L,46025L,46026L,46027L,46028L,46029L,46030L,46031L,46032L,
8431246033L,46034L,46035L,46036L,46037L,46038L,46039L,46040L,46041L,46042L,
8431346043L,46044L,46045L,46046L,46047L,46048L,46049L,46050L,46051L,46052L,
8431446053L,46054L,46055L,46056L,46057L,46058L,46059L,46060L,46061L,46062L,
8431546063L,46064L,46065L,46066L,46067L,46068L,46069L,46070L,46071L,46072L,
8431646073L,46074L,46075L,46076L,46077L,46078L,46079L,46080L,46081L,46082L,
8431746083L,46084L,46085L,46086L,46087L,46088L,46089L,46090L,46091L,46092L,
8431846093L,46094L,46095L,46096L,46097L,46098L,46099L,46100L,46101L,46102L,
8431946103L,46104L,46105L,46106L,46107L,46108L,46109L,46110L,46111L,46112L,
8432046113L,46114L,46115L,46116L,46117L,46118L,46119L,46120L,46121L,46122L,
8432146123L,46124L,46125L,46126L,46127L,46128L,46129L,46130L,46131L,46132L,
8432246133L,46134L,46135L,46136L,46137L,46138L,46139L,46140L,46141L,46142L,
8432346143L,46144L,46145L,46146L,46147L,46148L,46149L,46150L,46151L,46152L,
8432446153L,46154L,46155L,46156L,46157L,46158L,46159L,46160L,46161L,46162L,
8432546163L,46164L,46165L,46166L,46167L,46168L,46169L,46170L,46171L,46172L,
8432646173L,46174L,46175L,46176L,46177L,46178L,46179L,46180L,46181L,46182L,
8432746183L,46184L,46185L,46186L,46187L,46188L,46189L,46190L,46191L,46192L,
8432846193L,46194L,46195L,46196L,46197L,46198L,46199L,46200L,46201L,46202L,
8432946203L,46204L,46205L,46206L,46207L,46208L,46209L,46210L,46211L,46212L,
8433046213L,46214L,46215L,46216L,46217L,46218L,46219L,46220L,46221L,46222L,
8433146223L,46224L,46225L,46226L,46227L,46228L,46229L,46230L,46231L,46232L,
8433246233L,46234L,46235L,46236L,46237L,46238L,46239L,46240L,46241L,46242L,
8433346243L,46244L,46245L,46246L,46247L,46248L,46249L,46250L,46251L,46252L,
8433446253L,46254L,46255L,46256L,46257L,46258L,46259L,46260L,46261L,46262L,
8433546263L,46264L,46265L,46266L,46267L,46268L,46269L,46270L,46271L,46272L,
8433646273L,46274L,46275L,46276L,46277L,46278L,46279L,46280L,46281L,46282L,
8433746283L,46284L,46285L,46286L,46287L,46288L,46289L,46290L,46291L,46292L,
8433846293L,46294L,46295L,46296L,46297L,46298L,46299L,46300L,46301L,46302L,
8433946303L,46304L,46305L,46306L,46307L,46308L,46309L,46310L,46311L,46312L,
8434046313L,46314L,46315L,46316L,46317L,46318L,46319L,46320L,46321L,46322L,
8434146323L,46324L,46325L,46326L,46327L,46328L,46329L,46330L,46331L,46332L,
8434246333L,46334L,46335L,46336L,46337L,46338L,46339L,46340L,46341L,46342L,
8434346343L,46344L,46345L,46346L,46347L,46348L,46349L,46350L,46351L,46352L,
8434446353L,46354L,46355L,46356L,46357L,46358L,46359L,46360L,46361L,46362L,
8434546363L,46364L,46365L,46366L,46367L,46368L,46369L,46370L,46371L,46372L,
8434646373L,46374L,46375L,46376L,46377L,46378L,46379L,46380L,46381L,46382L,
8434746383L,46384L,46385L,46386L,46387L,46388L,46389L,46390L,46391L,46392L,
8434846393L,46394L,46395L,46396L,46397L,46398L,46399L,46400L,46401L,46402L,
8434946403L,46404L,46405L,46406L,46407L,46408L,46409L,46410L,46411L,46412L,
8435046413L,46414L,46415L,46416L,46417L,46418L,46419L,46420L,46421L,46422L,
8435146423L,46424L,46425L,46426L,46427L,46428L,46429L,46430L,46431L,46432L,
8435246433L,46434L,46435L,46436L,46437L,46438L,46439L,46440L,46441L,46442L,
8435346443L,46444L,46445L,46446L,46447L,46448L,46449L,46450L,46451L,46452L,
8435446453L,46454L,46455L,46456L,46457L,46458L,46459L,46460L,46461L,46462L,
8435546463L,46464L,46465L,46466L,46467L,46468L,46469L,46470L,46471L,46472L,
8435646473L,46474L,46475L,46476L,46477L,46478L,46479L,46480L,46481L,46482L,
8435746483L,46484L,46485L,46486L,46487L,46488L,46489L,46490L,46491L,46492L,
8435846493L,46494L,46495L,46496L,46497L,46498L,46499L,46500L,46501L,46502L,
8435946503L,46504L,46505L,46506L,46507L,46508L,46509L,46510L,46511L,46512L,
8436046513L,46514L,46515L,46516L,46517L,46518L,46519L,46520L,46521L,46522L,
8436146523L,46524L,46525L,46526L,46527L,46528L,46529L,46530L,46531L,46532L,
8436246533L,46534L,46535L,46536L,46537L,46538L,46539L,46540L,46541L,46542L,
8436346543L,46544L,46545L,46546L,46547L,46548L,46549L,46550L,46551L,46552L,
8436446553L,46554L,46555L,46556L,46557L,46558L,46559L,46560L,46561L,46562L,
8436546563L,46564L,46565L,46566L,46567L,46568L,46569L,46570L,46571L,46572L,
8436646573L,46574L,46575L,46576L,46577L,46578L,46579L,46580L,46581L,46582L,
8436746583L,46584L,46585L,46586L,46587L,46588L,46589L,46590L,46591L,46592L,
8436846593L,46594L,46595L,46596L,46597L,46598L,46599L,46600L,46601L,46602L,
8436946603L,46604L,46605L,46606L,46607L,46608L,46609L,46610L,46611L,46612L,
8437046613L,46614L,46615L,46616L,46617L,46618L,46619L,46620L,46621L,46622L,
8437146623L,46624L,46625L,46626L,46627L,46628L,46629L,46630L,46631L,46632L,
8437246633L,46634L,46635L,46636L,46637L,46638L,46639L,46640L,46641L,46642L,
8437346643L,46644L,46645L,46646L,46647L,46648L,46649L,46650L,46651L,46652L,
8437446653L,46654L,46655L,46656L,46657L,46658L,46659L,46660L,46661L,46662L,
8437546663L,46664L,46665L,46666L,46667L,46668L,46669L,46670L,46671L,46672L,
8437646673L,46674L,46675L,46676L,46677L,46678L,46679L,46680L,46681L,46682L,
8437746683L,46684L,46685L,46686L,46687L,46688L,46689L,46690L,46691L,46692L,
8437846693L,46694L,46695L,46696L,46697L,46698L,46699L,46700L,46701L,46702L,
8437946703L,46704L,46705L,46706L,46707L,46708L,46709L,46710L,46711L,46712L,
8438046713L,46714L,46715L,46716L,46717L,46718L,46719L,46720L,46721L,46722L,
8438146723L,46724L,46725L,46726L,46727L,46728L,46729L,46730L,46731L,46732L,
8438246733L,46734L,46735L,46736L,46737L,46738L,46739L,46740L,46741L,46742L,
8438346743L,46744L,46745L,46746L,46747L,46748L,46749L,46750L,46751L,46752L,
8438446753L,46754L,46755L,46756L,46757L,46758L,46759L,46760L,46761L,46762L,
8438546763L,46764L,46765L,46766L,46767L,46768L,46769L,46770L,46771L,46772L,
8438646773L,46774L,46775L,46776L,46777L,46778L,46779L,46780L,46781L,46782L,
8438746783L,46784L,46785L,46786L,46787L,46788L,46789L,46790L,46791L,46792L,
8438846793L,46794L,46795L,46796L,46797L,46798L,46799L,46800L,46801L,46802L,
8438946803L,46804L,46805L,46806L,46807L,46808L,46809L,46810L,46811L,46812L,
8439046813L,46814L,46815L,46816L,46817L,46818L,46819L,46820L,46821L,46822L,
8439146823L,46824L,46825L,46826L,46827L,46828L,46829L,46830L,46831L,46832L,
8439246833L,46834L,46835L,46836L,46837L,46838L,46839L,46840L,46841L,46842L,
8439346843L,46844L,46845L,46846L,46847L,46848L,46849L,46850L,46851L,46852L,
8439446853L,46854L,46855L,46856L,46857L,46858L,46859L,46860L,46861L,46862L,
8439546863L,46864L,46865L,46866L,46867L,46868L,46869L,46870L,46871L,46872L,
8439646873L,46874L,46875L,46876L,46877L,46878L,46879L,46880L,46881L,46882L,
8439746883L,46884L,46885L,46886L,46887L,46888L,46889L,46890L,46891L,46892L,
8439846893L,46894L,46895L,46896L,46897L,46898L,46899L,46900L,46901L,46902L,
8439946903L,46904L,46905L,46906L,46907L,46908L,46909L,46910L,46911L,46912L,
8440046913L,46914L,46915L,46916L,46917L,46918L,46919L,46920L,46921L,46922L,
8440146923L,46924L,46925L,46926L,46927L,46928L,46929L,46930L,46931L,46932L,
8440246933L,46934L,46935L,46936L,46937L,46938L,46939L,46940L,46941L,46942L,
8440346943L,46944L,46945L,46946L,46947L,46948L,46949L,46950L,46951L,46952L,
8440446953L,46954L,46955L,46956L,46957L,46958L,46959L,46960L,46961L,46962L,
8440546963L,46964L,46965L,46966L,46967L,46968L,46969L,46970L,46971L,46972L,
8440646973L,46974L,46975L,46976L,46977L,46978L,46979L,46980L,46981L,46982L,
8440746983L,46984L,46985L,46986L,46987L,46988L,46989L,46990L,46991L,46992L,
8440846993L,46994L,46995L,46996L,46997L,46998L,46999L,47000L,47001L,47002L,
8440947003L,47004L,47005L,47006L,47007L,47008L,47009L,47010L,47011L,47012L,
8441047013L,47014L,47015L,47016L,47017L,47018L,47019L,47020L,47021L,47022L,
8441147023L,47024L,47025L,47026L,47027L,47028L,47029L,47030L,47031L,47032L,
8441247033L,47034L,47035L,47036L,47037L,47038L,47039L,47040L,47041L,47042L,
8441347043L,47044L,47045L,47046L,47047L,47048L,47049L,47050L,47051L,47052L,
8441447053L,47054L,47055L,47056L,47057L,47058L,47059L,47060L,47061L,47062L,
8441547063L,47064L,47065L,47066L,47067L,47068L,47069L,47070L,47071L,47072L,
8441647073L,47074L,47075L,47076L,47077L,47078L,47079L,47080L,47081L,47082L,
8441747083L,47084L,47085L,47086L,47087L,47088L,47089L,47090L,47091L,47092L,
8441847093L,47094L,47095L,47096L,47097L,47098L,47099L,47100L,47101L,47102L,
8441947103L,47104L,47105L,47106L,47107L,47108L,47109L,47110L,47111L,47112L,
8442047113L,47114L,47115L,47116L,47117L,47118L,47119L,47120L,47121L,47122L,
8442147123L,47124L,47125L,47126L,47127L,47128L,47129L,47130L,47131L,47132L,
8442247133L,47134L,47135L,47136L,47137L,47138L,47139L,47140L,47141L,47142L,
8442347143L,47144L,47145L,47146L,47147L,47148L,47149L,47150L,47151L,47152L,
8442447153L,47154L,47155L,47156L,47157L,47158L,47159L,47160L,47161L,47162L,
8442547163L,47164L,47165L,47166L,47167L,47168L,47169L,47170L,47171L,47172L,
8442647173L,47174L,47175L,47176L,47177L,47178L,47179L,47180L,47181L,47182L,
8442747183L,47184L,47185L,47186L,47187L,47188L,47189L,47190L,47191L,47192L,
8442847193L,47194L,47195L,47196L,47197L,47198L,47199L,47200L,47201L,47202L,
8442947203L,47204L,47205L,47206L,47207L,47208L,47209L,47210L,47211L,47212L,
8443047213L,47214L,47215L,47216L,47217L,47218L,47219L,47220L,47221L,47222L,
8443147223L,47224L,47225L,47226L,47227L,47228L,47229L,47230L,47231L,47232L,
8443247233L,47234L,47235L,47236L,47237L,47238L,47239L,47240L,47241L,47242L,
8443347243L,47244L,47245L,47246L,47247L,47248L,47249L,47250L,47251L,47252L,
8443447253L,47254L,47255L,47256L,47257L,47258L,47259L,47260L,47261L,47262L,
8443547263L,47264L,47265L,47266L,47267L,47268L,47269L,47270L,47271L,47272L,
8443647273L,47274L,47275L,47276L,47277L,47278L,47279L,47280L,47281L,47282L,
8443747283L,47284L,47285L,47286L,47287L,47288L,47289L,47290L,47291L,47292L,
8443847293L,47294L,47295L,47296L,47297L,47298L,47299L,47300L,47301L,47302L,
8443947303L,47304L,47305L,47306L,47307L,47308L,47309L,47310L,47311L,47312L,
8444047313L,47314L,47315L,47316L,47317L,47318L,47319L,47320L,47321L,47322L,
8444147323L,47324L,47325L,47326L,47327L,47328L,47329L,47330L,47331L,47332L,
8444247333L,47334L,47335L,47336L,47337L,47338L,47339L,47340L,47341L,47342L,
8444347343L,47344L,47345L,47346L,47347L,47348L,47349L,47350L,47351L,47352L,
8444447353L,47354L,47355L,47356L,47357L,47358L,47359L,47360L,47361L,47362L,
8444547363L,47364L,47365L,47366L,47367L,47368L,47369L,47370L,47371L,47372L,
8444647373L,47374L,47375L,47376L,47377L,47378L,47379L,47380L,47381L,47382L,
8444747383L,47384L,47385L,47386L,47387L,47388L,47389L,47390L,47391L,47392L,
8444847393L,47394L,47395L,47396L,47397L,47398L,47399L,47400L,47401L,47402L,
8444947403L,47404L,47405L,47406L,47407L,47408L,47409L,47410L,47411L,47412L,
8445047413L,47414L,47415L,47416L,47417L,47418L,47419L,47420L,47421L,47422L,
8445147423L,47424L,47425L,47426L,47427L,47428L,47429L,47430L,47431L,47432L,
8445247433L,47434L,47435L,47436L,47437L,47438L,47439L,47440L,47441L,47442L,
8445347443L,47444L,47445L,47446L,47447L,47448L,47449L,47450L,47451L,47452L,
8445447453L,47454L,47455L,47456L,47457L,47458L,47459L,47460L,47461L,47462L,
8445547463L,47464L,47465L,47466L,47467L,47468L,47469L,47470L,47471L,47472L,
8445647473L,47474L,47475L,47476L,47477L,47478L,47479L,47480L,47481L,47482L,
8445747483L,47484L,47485L,47486L,47487L,47488L,47489L,47490L,47491L,47492L,
8445847493L,47494L,47495L,47496L,47497L,47498L,47499L,47500L,47501L,47502L,
8445947503L,47504L,47505L,47506L,47507L,47508L,47509L,47510L,47511L,47512L,
8446047513L,47514L,47515L,47516L,47517L,47518L,47519L,47520L,47521L,47522L,
8446147523L,47524L,47525L,47526L,47527L,47528L,47529L,47530L,47531L,47532L,
8446247533L,47534L,47535L,47536L,47537L,47538L,47539L,47540L,47541L,47542L,
8446347543L,47544L,47545L,47546L,47547L,47548L,47549L,47550L,47551L,47552L,
8446447553L,47554L,47555L,47556L,47557L,47558L,47559L,47560L,47561L,47562L,
8446547563L,47564L,47565L,47566L,47567L,47568L,47569L,47570L,47571L,47572L,
8446647573L,47574L,47575L,47576L,47577L,47578L,47579L,47580L,47581L,47582L,
8446747583L,47584L,47585L,47586L,47587L,47588L,47589L,47590L,47591L,47592L,
8446847593L,47594L,47595L,47596L,47597L,47598L,47599L,47600L,47601L,47602L,
8446947603L,47604L,47605L,47606L,47607L,47608L,47609L,47610L,47611L,47612L,
8447047613L,47614L,47615L,47616L,47617L,47618L,47619L,47620L,47621L,47622L,
8447147623L,47624L,47625L,47626L,47627L,47628L,47629L,47630L,47631L,47632L,
8447247633L,47634L,47635L,47636L,47637L,47638L,47639L,47640L,47641L,47642L,
8447347643L,47644L,47645L,47646L,47647L,47648L,47649L,47650L,47651L,47652L,
8447447653L,47654L,47655L,47656L,47657L,47658L,47659L,47660L,47661L,47662L,
8447547663L,47664L,47665L,47666L,47667L,47668L,47669L,47670L,47671L,47672L,
8447647673L,47674L,47675L,47676L,47677L,47678L,47679L,47680L,47681L,47682L,
8447747683L,47684L,47685L,47686L,47687L,47688L,47689L,47690L,47691L,47692L,
8447847693L,47694L,47695L,47696L,47697L,47698L,47699L,47700L,47701L,47702L,
8447947703L,47704L,47705L,47706L,47707L,47708L,47709L,47710L,47711L,47712L,
8448047713L,47714L,47715L,47716L,47717L,47718L,47719L,47720L,47721L,47722L,
8448147723L,47724L,47725L,47726L,47727L,47728L,47729L,47730L,47731L,47732L,
8448247733L,47734L,47735L,47736L,47737L,47738L,47739L,47740L,47741L,47742L,
8448347743L,47744L,47745L,47746L,47747L,47748L,47749L,47750L,47751L,47752L,
8448447753L,47754L,47755L,47756L,47757L,47758L,47759L,47760L,47761L,47762L,
8448547763L,47764L,47765L,47766L,47767L,47768L,47769L,47770L,47771L,47772L,
8448647773L,47774L,47775L,47776L,47777L,47778L,47779L,47780L,47781L,47782L,
8448747783L,47784L,47785L,47786L,47787L,47788L,47789L,47790L,47791L,47792L,
8448847793L,47794L,47795L,47796L,47797L,47798L,47799L,47800L,47801L,47802L,
8448947803L,47804L,47805L,47806L,47807L,47808L,47809L,47810L,47811L,47812L,
8449047813L,47814L,47815L,47816L,47817L,47818L,47819L,47820L,47821L,47822L,
8449147823L,47824L,47825L,47826L,47827L,47828L,47829L,47830L,47831L,47832L,
8449247833L,47834L,47835L,47836L,47837L,47838L,47839L,47840L,47841L,47842L,
8449347843L,47844L,47845L,47846L,47847L,47848L,47849L,47850L,47851L,47852L,
8449447853L,47854L,47855L,47856L,47857L,47858L,47859L,47860L,47861L,47862L,
8449547863L,47864L,47865L,47866L,47867L,47868L,47869L,47870L,47871L,47872L,
8449647873L,47874L,47875L,47876L,47877L,47878L,47879L,47880L,47881L,47882L,
8449747883L,47884L,47885L,47886L,47887L,47888L,47889L,47890L,47891L,47892L,
8449847893L,47894L,47895L,47896L,47897L,47898L,47899L,47900L,47901L,47902L,
8449947903L,47904L,47905L,47906L,47907L,47908L,47909L,47910L,47911L,47912L,
8450047913L,47914L,47915L,47916L,47917L,47918L,47919L,47920L,47921L,47922L,
8450147923L,47924L,47925L,47926L,47927L,47928L,47929L,47930L,47931L,47932L,
8450247933L,47934L,47935L,47936L,47937L,47938L,47939L,47940L,47941L,47942L,
8450347943L,47944L,47945L,47946L,47947L,47948L,47949L,47950L,47951L,47952L,
8450447953L,47954L,47955L,47956L,47957L,47958L,47959L,47960L,47961L,47962L,
8450547963L,47964L,47965L,47966L,47967L,47968L,47969L,47970L,47971L,47972L,
8450647973L,47974L,47975L,47976L,47977L,47978L,47979L,47980L,47981L,47982L,
8450747983L,47984L,47985L,47986L,47987L,47988L,47989L,47990L,47991L,47992L,
8450847993L,47994L,47995L,47996L,47997L,47998L,47999L,48000L,48001L,48002L,
8450948003L,48004L,48005L,48006L,48007L,48008L,48009L,48010L,48011L,48012L,
8451048013L,48014L,48015L,48016L,48017L,48018L,48019L,48020L,48021L,48022L,
8451148023L,48024L,48025L,48026L,48027L,48028L,48029L,48030L,48031L,48032L,
8451248033L,48034L,48035L,48036L,48037L,48038L,48039L,48040L,48041L,48042L,
8451348043L,48044L,48045L,48046L,48047L,48048L,48049L,48050L,48051L,48052L,
8451448053L,48054L,48055L,48056L,48057L,48058L,48059L,48060L,48061L,48062L,
8451548063L,48064L,48065L,48066L,48067L,48068L,48069L,48070L,48071L,48072L,
8451648073L,48074L,48075L,48076L,48077L,48078L,48079L,48080L,48081L,48082L,
8451748083L,48084L,48085L,48086L,48087L,48088L,48089L,48090L,48091L,48092L,
8451848093L,48094L,48095L,48096L,48097L,48098L,48099L,48100L,48101L,48102L,
8451948103L,48104L,48105L,48106L,48107L,48108L,48109L,48110L,48111L,48112L,
8452048113L,48114L,48115L,48116L,48117L,48118L,48119L,48120L,48121L,48122L,
8452148123L,48124L,48125L,48126L,48127L,48128L,48129L,48130L,48131L,48132L,
8452248133L,48134L,48135L,48136L,48137L,48138L,48139L,48140L,48141L,48142L,
8452348143L,48144L,48145L,48146L,48147L,48148L,48149L,48150L,48151L,48152L,
8452448153L,48154L,48155L,48156L,48157L,48158L,48159L,48160L,48161L,48162L,
8452548163L,48164L,48165L,48166L,48167L,48168L,48169L,48170L,48171L,48172L,
8452648173L,48174L,48175L,48176L,48177L,48178L,48179L,48180L,48181L,48182L,
8452748183L,48184L,48185L,48186L,48187L,48188L,48189L,48190L,48191L,48192L,
8452848193L,48194L,48195L,48196L,48197L,48198L,48199L,48200L,48201L,48202L,
8452948203L,48204L,48205L,48206L,48207L,48208L,48209L,48210L,48211L,48212L,
8453048213L,48214L,48215L,48216L,48217L,48218L,48219L,48220L,48221L,48222L,
8453148223L,48224L,48225L,48226L,48227L,48228L,48229L,48230L,48231L,48232L,
8453248233L,48234L,48235L,48236L,48237L,48238L,48239L,48240L,48241L,48242L,
8453348243L,48244L,48245L,48246L,48247L,48248L,48249L,48250L,48251L,48252L,
8453448253L,48254L,48255L,48256L,48257L,48258L,48259L,48260L,48261L,48262L,
8453548263L,48264L,48265L,48266L,48267L,48268L,48269L,48270L,48271L,48272L,
8453648273L,48274L,48275L,48276L,48277L,48278L,48279L,48280L,48281L,48282L,
8453748283L,48284L,48285L,48286L,48287L,48288L,48289L,48290L,48291L,48292L,
8453848293L,48294L,48295L,48296L,48297L,48298L,48299L,48300L,48301L,48302L,
8453948303L,48304L,48305L,48306L,48307L,48308L,48309L,48310L,48311L,48312L,
8454048313L,48314L,48315L,48316L,48317L,48318L,48319L,48320L,48321L,48322L,
8454148323L,48324L,48325L,48326L,48327L,48328L,48329L,48330L,48331L,48332L,
8454248333L,48334L,48335L,48336L,48337L,48338L,48339L,48340L,48341L,48342L,
8454348343L,48344L,48345L,48346L,48347L,48348L,48349L,48350L,48351L,48352L,
8454448353L,48354L,48355L,48356L,48357L,48358L,48359L,48360L,48361L,48362L,
8454548363L,48364L,48365L,48366L,48367L,48368L,48369L,48370L,48371L,48372L,
8454648373L,48374L,48375L,48376L,48377L,48378L,48379L,48380L,48381L,48382L,
8454748383L,48384L,48385L,48386L,48387L,48388L,48389L,48390L,48391L,48392L,
8454848393L,48394L,48395L,48396L,48397L,48398L,48399L,48400L,48401L,48402L,
8454948403L,48404L,48405L,48406L,48407L,48408L,48409L,48410L,48411L,48412L,
8455048413L,48414L,48415L,48416L,48417L,48418L,48419L,48420L,48421L,48422L,
8455148423L,48424L,48425L,48426L,48427L,48428L,48429L,48430L,48431L,48432L,
8455248433L,48434L,48435L,48436L,48437L,48438L,48439L,48440L,48441L,48442L,
8455348443L,48444L,48445L,48446L,48447L,48448L,48449L,48450L,48451L,48452L,
8455448453L,48454L,48455L,48456L,48457L,48458L,48459L,48460L,48461L,48462L,
8455548463L,48464L,48465L,48466L,48467L,48468L,48469L,48470L,48471L,48472L,
8455648473L,48474L,48475L,48476L,48477L,48478L,48479L,48480L,48481L,48482L,
8455748483L,48484L,48485L,48486L,48487L,48488L,48489L,48490L,48491L,48492L,
8455848493L,48494L,48495L,48496L,48497L,48498L,48499L,48500L,48501L,48502L,
8455948503L,48504L,48505L,48506L,48507L,48508L,48509L,48510L,48511L,48512L,
8456048513L,48514L,48515L,48516L,48517L,48518L,48519L,48520L,48521L,48522L,
8456148523L,48524L,48525L,48526L,48527L,48528L,48529L,48530L,48531L,48532L,
8456248533L,48534L,48535L,48536L,48537L,48538L,48539L,48540L,48541L,48542L,
8456348543L,48544L,48545L,48546L,48547L,48548L,48549L,48550L,48551L,48552L,
8456448553L,48554L,48555L,48556L,48557L,48558L,48559L,48560L,48561L,48562L,
8456548563L,48564L,48565L,48566L,48567L,48568L,48569L,48570L,48571L,48572L,
8456648573L,48574L,48575L,48576L,48577L,48578L,48579L,48580L,48581L,48582L,
8456748583L,48584L,48585L,48586L,48587L,48588L,48589L,48590L,48591L,48592L,
8456848593L,48594L,48595L,48596L,48597L,48598L,48599L,48600L,48601L,48602L,
8456948603L,48604L,48605L,48606L,48607L,48608L,48609L,48610L,48611L,48612L,
8457048613L,48614L,48615L,48616L,48617L,48618L,48619L,48620L,48621L,48622L,
8457148623L,48624L,48625L,48626L,48627L,48628L,48629L,48630L,48631L,48632L,
8457248633L,48634L,48635L,48636L,48637L,48638L,48639L,48640L,48641L,48642L,
8457348643L,48644L,48645L,48646L,48647L,48648L,48649L,48650L,48651L,48652L,
8457448653L,48654L,48655L,48656L,48657L,48658L,48659L,48660L,48661L,48662L,
8457548663L,48664L,48665L,48666L,48667L,48668L,48669L,48670L,48671L,48672L,
8457648673L,48674L,48675L,48676L,48677L,48678L,48679L,48680L,48681L,48682L,
8457748683L,48684L,48685L,48686L,48687L,48688L,48689L,48690L,48691L,48692L,
8457848693L,48694L,48695L,48696L,48697L,48698L,48699L,48700L,48701L,48702L,
8457948703L,48704L,48705L,48706L,48707L,48708L,48709L,48710L,48711L,48712L,
8458048713L,48714L,48715L,48716L,48717L,48718L,48719L,48720L,48721L,48722L,
8458148723L,48724L,48725L,48726L,48727L,48728L,48729L,48730L,48731L,48732L,
8458248733L,48734L,48735L,48736L,48737L,48738L,48739L,48740L,48741L,48742L,
8458348743L,48744L,48745L,48746L,48747L,48748L,48749L,48750L,48751L,48752L,
8458448753L,48754L,48755L,48756L,48757L,48758L,48759L,48760L,48761L,48762L,
8458548763L,48764L,48765L,48766L,48767L,48768L,48769L,48770L,48771L,48772L,
8458648773L,48774L,48775L,48776L,48777L,48778L,48779L,48780L,48781L,48782L,
8458748783L,48784L,48785L,48786L,48787L,48788L,48789L,48790L,48791L,48792L,
8458848793L,48794L,48795L,48796L,48797L,48798L,48799L,48800L,48801L,48802L,
8458948803L,48804L,48805L,48806L,48807L,48808L,48809L,48810L,48811L,48812L,
8459048813L,48814L,48815L,48816L,48817L,48818L,48819L,48820L,48821L,48822L,
8459148823L,48824L,48825L,48826L,48827L,48828L,48829L,48830L,48831L,48832L,
8459248833L,48834L,48835L,48836L,48837L,48838L,48839L,48840L,48841L,48842L,
8459348843L,48844L,48845L,48846L,48847L,48848L,48849L,48850L,48851L,48852L,
8459448853L,48854L,48855L,48856L,48857L,48858L,48859L,48860L,48861L,48862L,
8459548863L,48864L,48865L,48866L,48867L,48868L,48869L,48870L,48871L,48872L,
8459648873L,48874L,48875L,48876L,48877L,48878L,48879L,48880L,48881L,48882L,
8459748883L,48884L,48885L,48886L,48887L,48888L,48889L,48890L,48891L,48892L,
8459848893L,48894L,48895L,48896L,48897L,48898L,48899L,48900L,48901L,48902L,
8459948903L,48904L,48905L,48906L,48907L,48908L,48909L,48910L,48911L,48912L,
8460048913L,48914L,48915L,48916L,48917L,48918L,48919L,48920L,48921L,48922L,
8460148923L,48924L,48925L,48926L,48927L,48928L,48929L,48930L,48931L,48932L,
8460248933L,48934L,48935L,48936L,48937L,48938L,48939L,48940L,48941L,48942L,
8460348943L,48944L,48945L,48946L,48947L,48948L,48949L,48950L,48951L,48952L,
8460448953L,48954L,48955L,48956L,48957L,48958L,48959L,48960L,48961L,48962L,
8460548963L,48964L,48965L,48966L,48967L,48968L,48969L,48970L,48971L,48972L,
8460648973L,48974L,48975L,48976L,48977L,48978L,48979L,48980L,48981L,48982L,
8460748983L,48984L,48985L,48986L,48987L,48988L,48989L,48990L,48991L,48992L,
8460848993L,48994L,48995L,48996L,48997L,48998L,48999L,49000L,49001L,49002L,
8460949003L,49004L,49005L,49006L,49007L,49008L,49009L,49010L,49011L,49012L,
8461049013L,49014L,49015L,49016L,49017L,49018L,49019L,49020L,49021L,49022L,
8461149023L,49024L,49025L,49026L,49027L,49028L,49029L,49030L,49031L,49032L,
8461249033L,49034L,49035L,49036L,49037L,49038L,49039L,49040L,49041L,49042L,
8461349043L,49044L,49045L,49046L,49047L,49048L,49049L,49050L,49051L,49052L,
8461449053L,49054L,49055L,49056L,49057L,49058L,49059L,49060L,49061L,49062L,
8461549063L,49064L,49065L,49066L,49067L,49068L,49069L,49070L,49071L,49072L,
8461649073L,49074L,49075L,49076L,49077L,49078L,49079L,49080L,49081L,49082L,
8461749083L,49084L,49085L,49086L,49087L,49088L,49089L,49090L,49091L,49092L,
8461849093L,49094L,49095L,49096L,49097L,49098L,49099L,49100L,49101L,49102L,
8461949103L,49104L,49105L,49106L,49107L,49108L,49109L,49110L,49111L,49112L,
8462049113L,49114L,49115L,49116L,49117L,49118L,49119L,49120L,49121L,49122L,
8462149123L,49124L,49125L,49126L,49127L,49128L,49129L,49130L,49131L,49132L,
8462249133L,49134L,49135L,49136L,49137L,49138L,49139L,49140L,49141L,49142L,
8462349143L,49144L,49145L,49146L,49147L,49148L,49149L,49150L,49151L,49152L,
8462449153L,49154L,49155L,49156L,49157L,49158L,49159L,49160L,49161L,49162L,
8462549163L,49164L,49165L,49166L,49167L,49168L,49169L,49170L,49171L,49172L,
8462649173L,49174L,49175L,49176L,49177L,49178L,49179L,49180L,49181L,49182L,
8462749183L,49184L,49185L,49186L,49187L,49188L,49189L,49190L,49191L,49192L,
8462849193L,49194L,49195L,49196L,49197L,49198L,49199L,49200L,49201L,49202L,
8462949203L,49204L,49205L,49206L,49207L,49208L,49209L,49210L,49211L,49212L,
8463049213L,49214L,49215L,49216L,49217L,49218L,49219L,49220L,49221L,49222L,
8463149223L,49224L,49225L,49226L,49227L,49228L,49229L,49230L,49231L,49232L,
8463249233L,49234L,49235L,49236L,49237L,49238L,49239L,49240L,49241L,49242L,
8463349243L,49244L,49245L,49246L,49247L,49248L,49249L,49250L,49251L,49252L,
8463449253L,49254L,49255L,49256L,49257L,49258L,49259L,49260L,49261L,49262L,
8463549263L,49264L,49265L,49266L,49267L,49268L,49269L,49270L,49271L,49272L,
8463649273L,49274L,49275L,49276L,49277L,49278L,49279L,49280L,49281L,49282L,
8463749283L,49284L,49285L,49286L,49287L,49288L,49289L,49290L,49291L,49292L,
8463849293L,49294L,49295L,49296L,49297L,49298L,49299L,49300L,49301L,49302L,
8463949303L,49304L,49305L,49306L,49307L,49308L,49309L,49310L,49311L,49312L,
8464049313L,49314L,49315L,49316L,49317L,49318L,49319L,49320L,49321L,49322L,
8464149323L,49324L,49325L,49326L,49327L,49328L,49329L,49330L,49331L,49332L,
8464249333L,49334L,49335L,49336L,49337L,49338L,49339L,49340L,49341L,49342L,
8464349343L,49344L,49345L,49346L,49347L,49348L,49349L,49350L,49351L,49352L,
8464449353L,49354L,49355L,49356L,49357L,49358L,49359L,49360L,49361L,49362L,
8464549363L,49364L,49365L,49366L,49367L,49368L,49369L,49370L,49371L,49372L,
8464649373L,49374L,49375L,49376L,49377L,49378L,49379L,49380L,49381L,49382L,
8464749383L,49384L,49385L,49386L,49387L,49388L,49389L,49390L,49391L,49392L,
8464849393L,49394L,49395L,49396L,49397L,49398L,49399L,49400L,49401L,49402L,
8464949403L,49404L,49405L,49406L,49407L,49408L,49409L,49410L,49411L,49412L,
8465049413L,49414L,49415L,49416L,49417L,49418L,49419L,49420L,49421L,49422L,
8465149423L,49424L,49425L,49426L,49427L,49428L,49429L,49430L,49431L,49432L,
8465249433L,49434L,49435L,49436L,49437L,49438L,49439L,49440L,49441L,49442L,
8465349443L,49444L,49445L,49446L,49447L,49448L,49449L,49450L,49451L,49452L,
8465449453L,49454L,49455L,49456L,49457L,49458L,49459L,49460L,49461L,49462L,
8465549463L,49464L,49465L,49466L,49467L,49468L,49469L,49470L,49471L,49472L,
8465649473L,49474L,49475L,49476L,49477L,49478L,49479L,49480L,49481L,49482L,
8465749483L,49484L,49485L,49486L,49487L,49488L,49489L,49490L,49491L,49492L,
8465849493L,49494L,49495L,49496L,49497L,49498L,49499L,49500L,49501L,49502L,
8465949503L,49504L,49505L,49506L,49507L,49508L,49509L,49510L,49511L,49512L,
8466049513L,49514L,49515L,49516L,49517L,49518L,49519L,49520L,49521L,49522L,
8466149523L,49524L,49525L,49526L,49527L,49528L,49529L,49530L,49531L,49532L,
8466249533L,49534L,49535L,49536L,49537L,49538L,49539L,49540L,49541L,49542L,
8466349543L,49544L,49545L,49546L,49547L,49548L,49549L,49550L,49551L,49552L,
8466449553L,49554L,49555L,49556L,49557L,49558L,49559L,49560L,49561L,49562L,
8466549563L,49564L,49565L,49566L,49567L,49568L,49569L,49570L,49571L,49572L,
8466649573L,49574L,49575L,49576L,49577L,49578L,49579L,49580L,49581L,49582L,
8466749583L,49584L,49585L,49586L,49587L,49588L,49589L,49590L,49591L,49592L,
8466849593L,49594L,49595L,49596L,49597L,49598L,49599L,49600L,49601L,49602L,
8466949603L,49604L,49605L,49606L,49607L,49608L,49609L,49610L,49611L,49612L,
8467049613L,49614L,49615L,49616L,49617L,49618L,49619L,49620L,49621L,49622L,
8467149623L,49624L,49625L,49626L,49627L,49628L,49629L,49630L,49631L,49632L,
8467249633L,49634L,49635L,49636L,49637L,49638L,49639L,49640L,49641L,49642L,
8467349643L,49644L,49645L,49646L,49647L,49648L,49649L,49650L,49651L,49652L,
8467449653L,49654L,49655L,49656L,49657L,49658L,49659L,49660L,49661L,49662L,
8467549663L,49664L,49665L,49666L,49667L,49668L,49669L,49670L,49671L,49672L,
8467649673L,49674L,49675L,49676L,49677L,49678L,49679L,49680L,49681L,49682L,
8467749683L,49684L,49685L,49686L,49687L,49688L,49689L,49690L,49691L,49692L,
8467849693L,49694L,49695L,49696L,49697L,49698L,49699L,49700L,49701L,49702L,
8467949703L,49704L,49705L,49706L,49707L,49708L,49709L,49710L,49711L,49712L,
8468049713L,49714L,49715L,49716L,49717L,49718L,49719L,49720L,49721L,49722L,
8468149723L,49724L,49725L,49726L,49727L,49728L,49729L,49730L,49731L,49732L,
8468249733L,49734L,49735L,49736L,49737L,49738L,49739L,49740L,49741L,49742L,
8468349743L,49744L,49745L,49746L,49747L,49748L,49749L,49750L,49751L,49752L,
8468449753L,49754L,49755L,49756L,49757L,49758L,49759L,49760L,49761L,49762L,
8468549763L,49764L,49765L,49766L,49767L,49768L,49769L,49770L,49771L,49772L,
8468649773L,49774L,49775L,49776L,49777L,49778L,49779L,49780L,49781L,49782L,
8468749783L,49784L,49785L,49786L,49787L,49788L,49789L,49790L,49791L,49792L,
8468849793L,49794L,49795L,49796L,49797L,49798L,49799L,49800L,49801L,49802L,
8468949803L,49804L,49805L,49806L,49807L,49808L,49809L,49810L,49811L,49812L,
8469049813L,49814L,49815L,49816L,49817L,49818L,49819L,49820L,49821L,49822L,
8469149823L,49824L,49825L,49826L,49827L,49828L,49829L,49830L,49831L,49832L,
8469249833L,49834L,49835L,49836L,49837L,49838L,49839L,49840L,49841L,49842L,
8469349843L,49844L,49845L,49846L,49847L,49848L,49849L,49850L,49851L,49852L,
8469449853L,49854L,49855L,49856L,49857L,49858L,49859L,49860L,49861L,49862L,
8469549863L,49864L,49865L,49866L,49867L,49868L,49869L,49870L,49871L,49872L,
8469649873L,49874L,49875L,49876L,49877L,49878L,49879L,49880L,49881L,49882L,
8469749883L,49884L,49885L,49886L,49887L,49888L,49889L,49890L,49891L,49892L,
8469849893L,49894L,49895L,49896L,49897L,49898L,49899L,49900L,49901L,49902L,
8469949903L,49904L,49905L,49906L,49907L,49908L,49909L,49910L,49911L,49912L,
8470049913L,49914L,49915L,49916L,49917L,49918L,49919L,49920L,49921L,49922L,
8470149923L,49924L,49925L,49926L,49927L,49928L,49929L,49930L,49931L,49932L,
8470249933L,49934L,49935L,49936L,49937L,49938L,49939L,49940L,49941L,49942L,
8470349943L,49944L,49945L,49946L,49947L,49948L,49949L,49950L,49951L,49952L,
8470449953L,49954L,49955L,49956L,49957L,49958L,49959L,49960L,49961L,49962L,
8470549963L,49964L,49965L,49966L,49967L,49968L,49969L,49970L,49971L,49972L,
8470649973L,49974L,49975L,49976L,49977L,49978L,49979L,49980L,49981L,49982L,
8470749983L,49984L,49985L,49986L,49987L,49988L,49989L,49990L,49991L,49992L,
8470849993L,49994L,49995L,49996L,49997L,49998L,49999L,50000L,50001L,50002L,
8470950003L,50004L,50005L,50006L,50007L,50008L,50009L,50010L,50011L,50012L,
8471050013L,50014L,50015L,50016L,50017L,50018L,50019L,50020L,50021L,50022L,
8471150023L,50024L,50025L,50026L,50027L,50028L,50029L,50030L,50031L,50032L,
8471250033L,50034L,50035L,50036L,50037L,50038L,50039L,50040L,50041L,50042L,
8471350043L,50044L,50045L,50046L,50047L,50048L,50049L,50050L,50051L,50052L,
8471450053L,50054L,50055L,50056L,50057L,50058L,50059L,50060L,50061L,50062L,
8471550063L,50064L,50065L,50066L,50067L,50068L,50069L,50070L,50071L,50072L,
8471650073L,50074L,50075L,50076L,50077L,50078L,50079L,50080L,50081L,50082L,
8471750083L,50084L,50085L,50086L,50087L,50088L,50089L,50090L,50091L,50092L,
8471850093L,50094L,50095L,50096L,50097L,50098L,50099L,50100L,50101L,50102L,
8471950103L,50104L,50105L,50106L,50107L,50108L,50109L,50110L,50111L,50112L,
8472050113L,50114L,50115L,50116L,50117L,50118L,50119L,50120L,50121L,50122L,
8472150123L,50124L,50125L,50126L,50127L,50128L,50129L,50130L,50131L,50132L,
8472250133L,50134L,50135L,50136L,50137L,50138L,50139L,50140L,50141L,50142L,
8472350143L,50144L,50145L,50146L,50147L,50148L,50149L,50150L,50151L,50152L,
8472450153L,50154L,50155L,50156L,50157L,50158L,50159L,50160L,50161L,50162L,
8472550163L,50164L,50165L,50166L,50167L,50168L,50169L,50170L,50171L,50172L,
8472650173L,50174L,50175L,50176L,50177L,50178L,50179L,50180L,50181L,50182L,
8472750183L,50184L,50185L,50186L,50187L,50188L,50189L,50190L,50191L,50192L,
8472850193L,50194L,50195L,50196L,50197L,50198L,50199L,50200L,50201L,50202L,
8472950203L,50204L,50205L,50206L,50207L,50208L,50209L,50210L,50211L,50212L,
8473050213L,50214L,50215L,50216L,50217L,50218L,50219L,50220L,50221L,50222L,
8473150223L,50224L,50225L,50226L,50227L,50228L,50229L,50230L,50231L,50232L,
8473250233L,50234L,50235L,50236L,50237L,50238L,50239L,50240L,50241L,50242L,
8473350243L,50244L,50245L,50246L,50247L,50248L,50249L,50250L,50251L,50252L,
8473450253L,50254L,50255L,50256L,50257L,50258L,50259L,50260L,50261L,50262L,
8473550263L,50264L,50265L,50266L,50267L,50268L,50269L,50270L,50271L,50272L,
8473650273L,50274L,50275L,50276L,50277L,50278L,50279L,50280L,50281L,50282L,
8473750283L,50284L,50285L,50286L,50287L,50288L,50289L,50290L,50291L,50292L,
8473850293L,50294L,50295L,50296L,50297L,50298L,50299L,50300L,50301L,50302L,
8473950303L,50304L,50305L,50306L,50307L,50308L,50309L,50310L,50311L,50312L,
8474050313L,50314L,50315L,50316L,50317L,50318L,50319L,50320L,50321L,50322L,
8474150323L,50324L,50325L,50326L,50327L,50328L,50329L,50330L,50331L,50332L,
8474250333L,50334L,50335L,50336L,50337L,50338L,50339L,50340L,50341L,50342L,
8474350343L,50344L,50345L,50346L,50347L,50348L,50349L,50350L,50351L,50352L,
8474450353L,50354L,50355L,50356L,50357L,50358L,50359L,50360L,50361L,50362L,
8474550363L,50364L,50365L,50366L,50367L,50368L,50369L,50370L,50371L,50372L,
8474650373L,50374L,50375L,50376L,50377L,50378L,50379L,50380L,50381L,50382L,
8474750383L,50384L,50385L,50386L,50387L,50388L,50389L,50390L,50391L,50392L,
8474850393L,50394L,50395L,50396L,50397L,50398L,50399L,50400L,50401L,50402L,
8474950403L,50404L,50405L,50406L,50407L,50408L,50409L,50410L,50411L,50412L,
8475050413L,50414L,50415L,50416L,50417L,50418L,50419L,50420L,50421L,50422L,
8475150423L,50424L,50425L,50426L,50427L,50428L,50429L,50430L,50431L,50432L,
8475250433L,50434L,50435L,50436L,50437L,50438L,50439L,50440L,50441L,50442L,
8475350443L,50444L,50445L,50446L,50447L,50448L,50449L,50450L,50451L,50452L,
8475450453L,50454L,50455L,50456L,50457L,50458L,50459L,50460L,50461L,50462L,
8475550463L,50464L,50465L,50466L,50467L,50468L,50469L,50470L,50471L,50472L,
8475650473L,50474L,50475L,50476L,50477L,50478L,50479L,50480L,50481L,50482L,
8475750483L,50484L,50485L,50486L,50487L,50488L,50489L,50490L,50491L,50492L,
8475850493L,50494L,50495L,50496L,50497L,50498L,50499L,50500L,50501L,50502L,
8475950503L,50504L,50505L,50506L,50507L,50508L,50509L,50510L,50511L,50512L,
8476050513L,50514L,50515L,50516L,50517L,50518L,50519L,50520L,50521L,50522L,
8476150523L,50524L,50525L,50526L,50527L,50528L,50529L,50530L,50531L,50532L,
8476250533L,50534L,50535L,50536L,50537L,50538L,50539L,50540L,50541L,50542L,
8476350543L,50544L,50545L,50546L,50547L,50548L,50549L,50550L,50551L,50552L,
8476450553L,50554L,50555L,50556L,50557L,50558L,50559L,50560L,50561L,50562L,
8476550563L,50564L,50565L,50566L,50567L,50568L,50569L,50570L,50571L,50572L,
8476650573L,50574L,50575L,50576L,50577L,50578L,50579L,50580L,50581L,50582L,
8476750583L,50584L,50585L,50586L,50587L,50588L,50589L,50590L,50591L,50592L,
8476850593L,50594L,50595L,50596L,50597L,50598L,50599L,50600L,50601L,50602L,
8476950603L,50604L,50605L,50606L,50607L,50608L,50609L,50610L,50611L,50612L,
8477050613L,50614L,50615L,50616L,50617L,50618L,50619L,50620L,50621L,50622L,
8477150623L,50624L,50625L,50626L,50627L,50628L,50629L,50630L,50631L,50632L,
8477250633L,50634L,50635L,50636L,50637L,50638L,50639L,50640L,50641L,50642L,
8477350643L,50644L,50645L,50646L,50647L,50648L,50649L,50650L,50651L,50652L,
8477450653L,50654L,50655L,50656L,50657L,50658L,50659L,50660L,50661L,50662L,
8477550663L,50664L,50665L,50666L,50667L,50668L,50669L,50670L,50671L,50672L,
8477650673L,50674L,50675L,50676L,50677L,50678L,50679L,50680L,50681L,50682L,
8477750683L,50684L,50685L,50686L,50687L,50688L,50689L,50690L,50691L,50692L,
8477850693L,50694L,50695L,50696L,50697L,50698L,50699L,50700L,50701L,50702L,
8477950703L,50704L,50705L,50706L,50707L,50708L,50709L,50710L,50711L,50712L,
8478050713L,50714L,50715L,50716L,50717L,50718L,50719L,50720L,50721L,50722L,
8478150723L,50724L,50725L,50726L,50727L,50728L,50729L,50730L,50731L,50732L,
8478250733L,50734L,50735L,50736L,50737L,50738L,50739L,50740L,50741L,50742L,
8478350743L,50744L,50745L,50746L,50747L,50748L,50749L,50750L,50751L,50752L,
8478450753L,50754L,50755L,50756L,50757L,50758L,50759L,50760L,50761L,50762L,
8478550763L,50764L,50765L,50766L,50767L,50768L,50769L,50770L,50771L,50772L,
8478650773L,50774L,50775L,50776L,50777L,50778L,50779L,50780L,50781L,50782L,
8478750783L,50784L,50785L,50786L,50787L,50788L,50789L,50790L,50791L,50792L,
8478850793L,50794L,50795L,50796L,50797L,50798L,50799L,50800L,50801L,50802L,
8478950803L,50804L,50805L,50806L,50807L,50808L,50809L,50810L,50811L,50812L,
8479050813L,50814L,50815L,50816L,50817L,50818L,50819L,50820L,50821L,50822L,
8479150823L,50824L,50825L,50826L,50827L,50828L,50829L,50830L,50831L,50832L,
8479250833L,50834L,50835L,50836L,50837L,50838L,50839L,50840L,50841L,50842L,
8479350843L,50844L,50845L,50846L,50847L,50848L,50849L,50850L,50851L,50852L,
8479450853L,50854L,50855L,50856L,50857L,50858L,50859L,50860L,50861L,50862L,
8479550863L,50864L,50865L,50866L,50867L,50868L,50869L,50870L,50871L,50872L,
8479650873L,50874L,50875L,50876L,50877L,50878L,50879L,50880L,50881L,50882L,
8479750883L,50884L,50885L,50886L,50887L,50888L,50889L,50890L,50891L,50892L,
8479850893L,50894L,50895L,50896L,50897L,50898L,50899L,50900L,50901L,50902L,
8479950903L,50904L,50905L,50906L,50907L,50908L,50909L,50910L,50911L,50912L,
8480050913L,50914L,50915L,50916L,50917L,50918L,50919L,50920L,50921L,50922L,
8480150923L,50924L,50925L,50926L,50927L,50928L,50929L,50930L,50931L,50932L,
8480250933L,50934L,50935L,50936L,50937L,50938L,50939L,50940L,50941L,50942L,
8480350943L,50944L,50945L,50946L,50947L,50948L,50949L,50950L,50951L,50952L,
8480450953L,50954L,50955L,50956L,50957L,50958L,50959L,50960L,50961L,50962L,
8480550963L,50964L,50965L,50966L,50967L,50968L,50969L,50970L,50971L,50972L,
8480650973L,50974L,50975L,50976L,50977L,50978L,50979L,50980L,50981L,50982L,
8480750983L,50984L,50985L,50986L,50987L,50988L,50989L,50990L,50991L,50992L,
8480850993L,50994L,50995L,50996L,50997L,50998L,50999L,51000L,51001L,51002L,
8480951003L,51004L,51005L,51006L,51007L,51008L,51009L,51010L,51011L,51012L,
8481051013L,51014L,51015L,51016L,51017L,51018L,51019L,51020L,51021L,51022L,
8481151023L,51024L,51025L,51026L,51027L,51028L,51029L,51030L,51031L,51032L,
8481251033L,51034L,51035L,51036L,51037L,51038L,51039L,51040L,51041L,51042L,
8481351043L,51044L,51045L,51046L,51047L,51048L,51049L,51050L,51051L,51052L,
8481451053L,51054L,51055L,51056L,51057L,51058L,51059L,51060L,51061L,51062L,
8481551063L,51064L,51065L,51066L,51067L,51068L,51069L,51070L,51071L,51072L,
8481651073L,51074L,51075L,51076L,51077L,51078L,51079L,51080L,51081L,51082L,
8481751083L,51084L,51085L,51086L,51087L,51088L,51089L,51090L,51091L,51092L,
8481851093L,51094L,51095L,51096L,51097L,51098L,51099L,51100L,51101L,51102L,
8481951103L,51104L,51105L,51106L,51107L,51108L,51109L,51110L,51111L,51112L,
8482051113L,51114L,51115L,51116L,51117L,51118L,51119L,51120L,51121L,51122L,
8482151123L,51124L,51125L,51126L,51127L,51128L,51129L,51130L,51131L,51132L,
8482251133L,51134L,51135L,51136L,51137L,51138L,51139L,51140L,51141L,51142L,
8482351143L,51144L,51145L,51146L,51147L,51148L,51149L,51150L,51151L,51152L,
8482451153L,51154L,51155L,51156L,51157L,51158L,51159L,51160L,51161L,51162L,
8482551163L,51164L,51165L,51166L,51167L,51168L,51169L,51170L,51171L,51172L,
8482651173L,51174L,51175L,51176L,51177L,51178L,51179L,51180L,51181L,51182L,
8482751183L,51184L,51185L,51186L,51187L,51188L,51189L,51190L,51191L,51192L,
8482851193L,51194L,51195L,51196L,51197L,51198L,51199L,51200L,51201L,51202L,
8482951203L,51204L,51205L,51206L,51207L,51208L,51209L,51210L,51211L,51212L,
8483051213L,51214L,51215L,51216L,51217L,51218L,51219L,51220L,51221L,51222L,
8483151223L,51224L,51225L,51226L,51227L,51228L,51229L,51230L,51231L,51232L,
8483251233L,51234L,51235L,51236L,51237L,51238L,51239L,51240L,51241L,51242L,
8483351243L,51244L,51245L,51246L,51247L,51248L,51249L,51250L,51251L,51252L,
8483451253L,51254L,51255L,51256L,51257L,51258L,51259L,51260L,51261L,51262L,
8483551263L,51264L,51265L,51266L,51267L,51268L,51269L,51270L,51271L,51272L,
8483651273L,51274L,51275L,51276L,51277L,51278L,51279L,51280L,51281L,51282L,
8483751283L,51284L,51285L,51286L,51287L,51288L,51289L,51290L,51291L,51292L,
8483851293L,51294L,51295L,51296L,51297L,51298L,51299L,51300L,51301L,51302L,
8483951303L,51304L,51305L,51306L,51307L,51308L,51309L,51310L,51311L,51312L,
8484051313L,51314L,51315L,51316L,51317L,51318L,51319L,51320L,51321L,51322L,
8484151323L,51324L,51325L,51326L,51327L,51328L,51329L,51330L,51331L,51332L,
8484251333L,51334L,51335L,51336L,51337L,51338L,51339L,51340L,51341L,51342L,
8484351343L,51344L,51345L,51346L,51347L,51348L,51349L,51350L,51351L,51352L,
8484451353L,51354L,51355L,51356L,51357L,51358L,51359L,51360L,51361L,51362L,
8484551363L,51364L,51365L,51366L,51367L,51368L,51369L,51370L,51371L,51372L,
8484651373L,51374L,51375L,51376L,51377L,51378L,51379L,51380L,51381L,51382L,
8484751383L,51384L,51385L,51386L,51387L,51388L,51389L,51390L,51391L,51392L,
8484851393L,51394L,51395L,51396L,51397L,51398L,51399L,51400L,51401L,51402L,
8484951403L,51404L,51405L,51406L,51407L,51408L,51409L,51410L,51411L,51412L,
8485051413L,51414L,51415L,51416L,51417L,51418L,51419L,51420L,51421L,51422L,
8485151423L,51424L,51425L,51426L,51427L,51428L,51429L,51430L,51431L,51432L,
8485251433L,51434L,51435L,51436L,51437L,51438L,51439L,51440L,51441L,51442L,
8485351443L,51444L,51445L,51446L,51447L,51448L,51449L,51450L,51451L,51452L,
8485451453L,51454L,51455L,51456L,51457L,51458L,51459L,51460L,51461L,51462L,
8485551463L,51464L,51465L,51466L,51467L,51468L,51469L,51470L,51471L,51472L,
8485651473L,51474L,51475L,51476L,51477L,51478L,51479L,51480L,51481L,51482L,
8485751483L,51484L,51485L,51486L,51487L,51488L,51489L,51490L,51491L,51492L,
8485851493L,51494L,51495L,51496L,51497L,51498L,51499L,51500L,51501L,51502L,
8485951503L,51504L,51505L,51506L,51507L,51508L,51509L,51510L,51511L,51512L,
8486051513L,51514L,51515L,51516L,51517L,51518L,51519L,51520L,51521L,51522L,
8486151523L,51524L,51525L,51526L,51527L,51528L,51529L,51530L,51531L,51532L,
8486251533L,51534L,51535L,51536L,51537L,51538L,51539L,51540L,51541L,51542L,
8486351543L,51544L,51545L,51546L,51547L,51548L,51549L,51550L,51551L,51552L,
8486451553L,51554L,51555L,51556L,51557L,51558L,51559L,51560L,51561L,51562L,
8486551563L,51564L,51565L,51566L,51567L,51568L,51569L,51570L,51571L,51572L,
8486651573L,51574L,51575L,51576L,51577L,51578L,51579L,51580L,51581L,51582L,
8486751583L,51584L,51585L,51586L,51587L,51588L,51589L,51590L,51591L,51592L,
8486851593L,51594L,51595L,51596L,51597L,51598L,51599L,51600L,51601L,51602L,
8486951603L,51604L,51605L,51606L,51607L,51608L,51609L,51610L,51611L,51612L,
8487051613L,51614L,51615L,51616L,51617L,51618L,51619L,51620L,51621L,51622L,
8487151623L,51624L,51625L,51626L,51627L,51628L,51629L,51630L,51631L,51632L,
8487251633L,51634L,51635L,51636L,51637L,51638L,51639L,51640L,51641L,51642L,
8487351643L,51644L,51645L,51646L,51647L,51648L,51649L,51650L,51651L,51652L,
8487451653L,51654L,51655L,51656L,51657L,51658L,51659L,51660L,51661L,51662L,
8487551663L,51664L,51665L,51666L,51667L,51668L,51669L,51670L,51671L,51672L,
8487651673L,51674L,51675L,51676L,51677L,51678L,51679L,51680L,51681L,51682L,
8487751683L,51684L,51685L,51686L,51687L,51688L,51689L,51690L,51691L,51692L,
8487851693L,51694L,51695L,51696L,51697L,51698L,51699L,51700L,51701L,51702L,
8487951703L,51704L,51705L,51706L,51707L,51708L,51709L,51710L,51711L,51712L,
8488051713L,51714L,51715L,51716L,51717L,51718L,51719L,51720L,51721L,51722L,
8488151723L,51724L,51725L,51726L,51727L,51728L,51729L,51730L,51731L,51732L,
8488251733L,51734L,51735L,51736L,51737L,51738L,51739L,51740L,51741L,51742L,
8488351743L,51744L,51745L,51746L,51747L,51748L,51749L,51750L,51751L,51752L,
8488451753L,51754L,51755L,51756L,51757L,51758L,51759L,51760L,51761L,51762L,
8488551763L,51764L,51765L,51766L,51767L,51768L,51769L,51770L,51771L,51772L,
8488651773L,51774L,51775L,51776L,51777L,51778L,51779L,51780L,51781L,51782L,
8488751783L,51784L,51785L,51786L,51787L,51788L,51789L,51790L,51791L,51792L,
8488851793L,51794L,51795L,51796L,51797L,51798L,51799L,51800L,51801L,51802L,
8488951803L,51804L,51805L,51806L,51807L,51808L,51809L,51810L,51811L,51812L,
8489051813L,51814L,51815L,51816L,51817L,51818L,51819L,51820L,51821L,51822L,
8489151823L,51824L,51825L,51826L,51827L,51828L,51829L,51830L,51831L,51832L,
8489251833L,51834L,51835L,51836L,51837L,51838L,51839L,51840L,51841L,51842L,
8489351843L,51844L,51845L,51846L,51847L,51848L,51849L,51850L,51851L,51852L,
8489451853L,51854L,51855L,51856L,51857L,51858L,51859L,51860L,51861L,51862L,
8489551863L,51864L,51865L,51866L,51867L,51868L,51869L,51870L,51871L,51872L,
8489651873L,51874L,51875L,51876L,51877L,51878L,51879L,51880L,51881L,51882L,
8489751883L,51884L,51885L,51886L,51887L,51888L,51889L,51890L,51891L,51892L,
8489851893L,51894L,51895L,51896L,51897L,51898L,51899L,51900L,51901L,51902L,
8489951903L,51904L,51905L,51906L,51907L,51908L,51909L,51910L,51911L,51912L,
8490051913L,51914L,51915L,51916L,51917L,51918L,51919L,51920L,51921L,51922L,
8490151923L,51924L,51925L,51926L,51927L,51928L,51929L,51930L,51931L,51932L,
8490251933L,51934L,51935L,51936L,51937L,51938L,51939L,51940L,51941L,51942L,
8490351943L,51944L,51945L,51946L,51947L,51948L,51949L,51950L,51951L,51952L,
8490451953L,51954L,51955L,51956L,51957L,51958L,51959L,51960L,51961L,51962L,
8490551963L,51964L,51965L,51966L,51967L,51968L,51969L,51970L,51971L,51972L,
8490651973L,51974L,51975L,51976L,51977L,51978L,51979L,51980L,51981L,51982L,
8490751983L,51984L,51985L,51986L,51987L,51988L,51989L,51990L,51991L,51992L,
8490851993L,51994L,51995L,51996L,51997L,51998L,51999L,52000L,52001L,52002L,
8490952003L,52004L,52005L,52006L,52007L,52008L,52009L,52010L,52011L,52012L,
8491052013L,52014L,52015L,52016L,52017L,52018L,52019L,52020L,52021L,52022L,
8491152023L,52024L,52025L,52026L,52027L,52028L,52029L,52030L,52031L,52032L,
8491252033L,52034L,52035L,52036L,52037L,52038L,52039L,52040L,52041L,52042L,
8491352043L,52044L,52045L,52046L,52047L,52048L,52049L,52050L,52051L,52052L,
8491452053L,52054L,52055L,52056L,52057L,52058L,52059L,52060L,52061L,52062L,
8491552063L,52064L,52065L,52066L,52067L,52068L,52069L,52070L,52071L,52072L,
8491652073L,52074L,52075L,52076L,52077L,52078L,52079L,52080L,52081L,52082L,
8491752083L,52084L,52085L,52086L,52087L,52088L,52089L,52090L,52091L,52092L,
8491852093L,52094L,52095L,52096L,52097L,52098L,52099L,52100L,52101L,52102L,
8491952103L,52104L,52105L,52106L,52107L,52108L,52109L,52110L,52111L,52112L,
8492052113L,52114L,52115L,52116L,52117L,52118L,52119L,52120L,52121L,52122L,
8492152123L,52124L,52125L,52126L,52127L,52128L,52129L,52130L,52131L,52132L,
8492252133L,52134L,52135L,52136L,52137L,52138L,52139L,52140L,52141L,52142L,
8492352143L,52144L,52145L,52146L,52147L,52148L,52149L,52150L,52151L,52152L,
8492452153L,52154L,52155L,52156L,52157L,52158L,52159L,52160L,52161L,52162L,
8492552163L,52164L,52165L,52166L,52167L,52168L,52169L,52170L,52171L,52172L,
8492652173L,52174L,52175L,52176L,52177L,52178L,52179L,52180L,52181L,52182L,
8492752183L,52184L,52185L,52186L,52187L,52188L,52189L,52190L,52191L,52192L,
8492852193L,52194L,52195L,52196L,52197L,52198L,52199L,52200L,52201L,52202L,
8492952203L,52204L,52205L,52206L,52207L,52208L,52209L,52210L,52211L,52212L,
8493052213L,52214L,52215L,52216L,52217L,52218L,52219L,52220L,52221L,52222L,
8493152223L,52224L,52225L,52226L,52227L,52228L,52229L,52230L,52231L,52232L,
8493252233L,52234L,52235L,52236L,52237L,52238L,52239L,52240L,52241L,52242L,
8493352243L,52244L,52245L,52246L,52247L,52248L,52249L,52250L,52251L,52252L,
8493452253L,52254L,52255L,52256L,52257L,52258L,52259L,52260L,52261L,52262L,
8493552263L,52264L,52265L,52266L,52267L,52268L,52269L,52270L,52271L,52272L,
8493652273L,52274L,52275L,52276L,52277L,52278L,52279L,52280L,52281L,52282L,
8493752283L,52284L,52285L,52286L,52287L,52288L,52289L,52290L,52291L,52292L,
8493852293L,52294L,52295L,52296L,52297L,52298L,52299L,52300L,52301L,52302L,
8493952303L,52304L,52305L,52306L,52307L,52308L,52309L,52310L,52311L,52312L,
8494052313L,52314L,52315L,52316L,52317L,52318L,52319L,52320L,52321L,52322L,
8494152323L,52324L,52325L,52326L,52327L,52328L,52329L,52330L,52331L,52332L,
8494252333L,52334L,52335L,52336L,52337L,52338L,52339L,52340L,52341L,52342L,
8494352343L,52344L,52345L,52346L,52347L,52348L,52349L,52350L,52351L,52352L,
8494452353L,52354L,52355L,52356L,52357L,52358L,52359L,52360L,52361L,52362L,
8494552363L,52364L,52365L,52366L,52367L,52368L,52369L,52370L,52371L,52372L,
8494652373L,52374L,52375L,52376L,52377L,52378L,52379L,52380L,52381L,52382L,
8494752383L,52384L,52385L,52386L,52387L,52388L,52389L,52390L,52391L,52392L,
8494852393L,52394L,52395L,52396L,52397L,52398L,52399L,52400L,52401L,52402L,
8494952403L,52404L,52405L,52406L,52407L,52408L,52409L,52410L,52411L,52412L,
8495052413L,52414L,52415L,52416L,52417L,52418L,52419L,52420L,52421L,52422L,
8495152423L,52424L,52425L,52426L,52427L,52428L,52429L,52430L,52431L,52432L,
8495252433L,52434L,52435L,52436L,52437L,52438L,52439L,52440L,52441L,52442L,
8495352443L,52444L,52445L,52446L,52447L,52448L,52449L,52450L,52451L,52452L,
8495452453L,52454L,52455L,52456L,52457L,52458L,52459L,52460L,52461L,52462L,
8495552463L,52464L,52465L,52466L,52467L,52468L,52469L,52470L,52471L,52472L,
8495652473L,52474L,52475L,52476L,52477L,52478L,52479L,52480L,52481L,52482L,
8495752483L,52484L,52485L,52486L,52487L,52488L,52489L,52490L,52491L,52492L,
8495852493L,52494L,52495L,52496L,52497L,52498L,52499L,52500L,52501L,52502L,
8495952503L,52504L,52505L,52506L,52507L,52508L,52509L,52510L,52511L,52512L,
8496052513L,52514L,52515L,52516L,52517L,52518L,52519L,52520L,52521L,52522L,
8496152523L,52524L,52525L,52526L,52527L,52528L,52529L,52530L,52531L,52532L,
8496252533L,52534L,52535L,52536L,52537L,52538L,52539L,52540L,52541L,52542L,
8496352543L,52544L,52545L,52546L,52547L,52548L,52549L,52550L,52551L,52552L,
8496452553L,52554L,52555L,52556L,52557L,52558L,52559L,52560L,52561L,52562L,
8496552563L,52564L,52565L,52566L,52567L,52568L,52569L,52570L,52571L,52572L,
8496652573L,52574L,52575L,52576L,52577L,52578L,52579L,52580L,52581L,52582L,
8496752583L,52584L,52585L,52586L,52587L,52588L,52589L,52590L,52591L,52592L,
8496852593L,52594L,52595L,52596L,52597L,52598L,52599L,52600L,52601L,52602L,
8496952603L,52604L,52605L,52606L,52607L,52608L,52609L,52610L,52611L,52612L,
8497052613L,52614L,52615L,52616L,52617L,52618L,52619L,52620L,52621L,52622L,
8497152623L,52624L,52625L,52626L,52627L,52628L,52629L,52630L,52631L,52632L,
8497252633L,52634L,52635L,52636L,52637L,52638L,52639L,52640L,52641L,52642L,
8497352643L,52644L,52645L,52646L,52647L,52648L,52649L,52650L,52651L,52652L,
8497452653L,52654L,52655L,52656L,52657L,52658L,52659L,52660L,52661L,52662L,
8497552663L,52664L,52665L,52666L,52667L,52668L,52669L,52670L,52671L,52672L,
8497652673L,52674L,52675L,52676L,52677L,52678L,52679L,52680L,52681L,52682L,
8497752683L,52684L,52685L,52686L,52687L,52688L,52689L,52690L,52691L,52692L,
8497852693L,52694L,52695L,52696L,52697L,52698L,52699L,52700L,52701L,52702L,
8497952703L,52704L,52705L,52706L,52707L,52708L,52709L,52710L,52711L,52712L,
8498052713L,52714L,52715L,52716L,52717L,52718L,52719L,52720L,52721L,52722L,
8498152723L,52724L,52725L,52726L,52727L,52728L,52729L,52730L,52731L,52732L,
8498252733L,52734L,52735L,52736L,52737L,52738L,52739L,52740L,52741L,52742L,
8498352743L,52744L,52745L,52746L,52747L,52748L,52749L,52750L,52751L,52752L,
8498452753L,52754L,52755L,52756L,52757L,52758L,52759L,52760L,52761L,52762L,
8498552763L,52764L,52765L,52766L,52767L,52768L,52769L,52770L,52771L,52772L,
8498652773L,52774L,52775L,52776L,52777L,52778L,52779L,52780L,52781L,52782L,
8498752783L,52784L,52785L,52786L,52787L,52788L,52789L,52790L,52791L,52792L,
8498852793L,52794L,52795L,52796L,52797L,52798L,52799L,52800L,52801L,52802L,
8498952803L,52804L,52805L,52806L,52807L,52808L,52809L,52810L,52811L,52812L,
8499052813L,52814L,52815L,52816L,52817L,52818L,52819L,52820L,52821L,52822L,
8499152823L,52824L,52825L,52826L,52827L,52828L,52829L,52830L,52831L,52832L,
8499252833L,52834L,52835L,52836L,52837L,52838L,52839L,52840L,52841L,52842L,
8499352843L,52844L,52845L,52846L,52847L,52848L,52849L,52850L,52851L,52852L,
8499452853L,52854L,52855L,52856L,52857L,52858L,52859L,52860L,52861L,52862L,
8499552863L,52864L,52865L,52866L,52867L,52868L,52869L,52870L,52871L,52872L,
8499652873L,52874L,52875L,52876L,52877L,52878L,52879L,52880L,52881L,52882L,
8499752883L,52884L,52885L,52886L,52887L,52888L,52889L,52890L,52891L,52892L,
8499852893L,52894L,52895L,52896L,52897L,52898L,52899L,52900L,52901L,52902L,
8499952903L,52904L,52905L,52906L,52907L,52908L,52909L,52910L,52911L,52912L,
8500052913L,52914L,52915L,52916L,52917L,52918L,52919L,52920L,52921L,52922L,
8500152923L,52924L,52925L,52926L,52927L,52928L,52929L,52930L,52931L,52932L,
8500252933L,52934L,52935L,52936L,52937L,52938L,52939L,52940L,52941L,52942L,
8500352943L,52944L,52945L,52946L,52947L,52948L,52949L,52950L,52951L,52952L,
8500452953L,52954L,52955L,52956L,52957L,52958L,52959L,52960L,52961L,52962L,
8500552963L,52964L,52965L,52966L,52967L,52968L,52969L,52970L,52971L,52972L,
8500652973L,52974L,52975L,52976L,52977L,52978L,52979L,52980L,52981L,52982L,
8500752983L,52984L,52985L,52986L,52987L,52988L,52989L,52990L,52991L,52992L,
8500852993L,52994L,52995L,52996L,52997L,52998L,52999L,53000L,53001L,53002L,
8500953003L,53004L,53005L,53006L,53007L,53008L,53009L,53010L,53011L,53012L,
8501053013L,53014L,53015L,53016L,53017L,53018L,53019L,53020L,53021L,53022L,
8501153023L,53024L,53025L,53026L,53027L,53028L,53029L,53030L,53031L,53032L,
8501253033L,53034L,53035L,53036L,53037L,53038L,53039L,53040L,53041L,53042L,
8501353043L,53044L,53045L,53046L,53047L,53048L,53049L,53050L,53051L,53052L,
8501453053L,53054L,53055L,53056L,53057L,53058L,53059L,53060L,53061L,53062L,
8501553063L,53064L,53065L,53066L,53067L,53068L,53069L,53070L,53071L,53072L,
8501653073L,53074L,53075L,53076L,53077L,53078L,53079L,53080L,53081L,53082L,
8501753083L,53084L,53085L,53086L,53087L,53088L,53089L,53090L,53091L,53092L,
8501853093L,53094L,53095L,53096L,53097L,53098L,53099L,53100L,53101L,53102L,
8501953103L,53104L,53105L,53106L,53107L,53108L,53109L,53110L,53111L,53112L,
8502053113L,53114L,53115L,53116L,53117L,53118L,53119L,53120L,53121L,53122L,
8502153123L,53124L,53125L,53126L,53127L,53128L,53129L,53130L,53131L,53132L,
8502253133L,53134L,53135L,53136L,53137L,53138L,53139L,53140L,53141L,53142L,
8502353143L,53144L,53145L,53146L,53147L,53148L,53149L,53150L,53151L,53152L,
8502453153L,53154L,53155L,53156L,53157L,53158L,53159L,53160L,53161L,53162L,
8502553163L,53164L,53165L,53166L,53167L,53168L,53169L,53170L,53171L,53172L,
8502653173L,53174L,53175L,53176L,53177L,53178L,53179L,53180L,53181L,53182L,
8502753183L,53184L,53185L,53186L,53187L,53188L,53189L,53190L,53191L,53192L,
8502853193L,53194L,53195L,53196L,53197L,53198L,53199L,53200L,53201L,53202L,
8502953203L,53204L,53205L,53206L,53207L,53208L,53209L,53210L,53211L,53212L,
8503053213L,53214L,53215L,53216L,53217L,53218L,53219L,53220L,53221L,53222L,
8503153223L,53224L,53225L,53226L,53227L,53228L,53229L,53230L,53231L,53232L,
8503253233L,53234L,53235L,53236L,53237L,53238L,53239L,53240L,53241L,53242L,
8503353243L,53244L,53245L,53246L,53247L,53248L,53249L,53250L,53251L,53252L,
8503453253L,53254L,53255L,53256L,53257L,53258L,53259L,53260L,53261L,53262L,
8503553263L,53264L,53265L,53266L,53267L,53268L,53269L,53270L,53271L,53272L,
8503653273L,53274L,53275L,53276L,53277L,53278L,53279L,53280L,53281L,53282L,
8503753283L,53284L,53285L,53286L,53287L,53288L,53289L,53290L,53291L,53292L,
8503853293L,53294L,53295L,53296L,53297L,53298L,53299L,53300L,53301L,53302L,
8503953303L,53304L,53305L,53306L,53307L,53308L,53309L,53310L,53311L,53312L,
8504053313L,53314L,53315L,53316L,53317L,53318L,53319L,53320L,53321L,53322L,
8504153323L,53324L,53325L,53326L,53327L,53328L,53329L,53330L,53331L,53332L,
8504253333L,53334L,53335L,53336L,53337L,53338L,53339L,53340L,53341L,53342L,
8504353343L,53344L,53345L,53346L,53347L,53348L,53349L,53350L,53351L,53352L,
8504453353L,53354L,53355L,53356L,53357L,53358L,53359L,53360L,53361L,53362L,
8504553363L,53364L,53365L,53366L,53367L,53368L,53369L,53370L,53371L,53372L,
8504653373L,53374L,53375L,53376L,53377L,53378L,53379L,53380L,53381L,53382L,
8504753383L,53384L,53385L,53386L,53387L,53388L,53389L,53390L,53391L,53392L,
8504853393L,53394L,53395L,53396L,53397L,53398L,53399L,53400L,53401L,53402L,
8504953403L,53404L,53405L,53406L,53407L,53408L,53409L,53410L,53411L,53412L,
8505053413L,53414L,53415L,53416L,53417L,53418L,53419L,53420L,53421L,53422L,
8505153423L,53424L,53425L,53426L,53427L,53428L,53429L,53430L,53431L,53432L,
8505253433L,53434L,53435L,53436L,53437L,53438L,53439L,53440L,53441L,53442L,
8505353443L,53444L,53445L,53446L,53447L,53448L,53449L,53450L,53451L,53452L,
8505453453L,53454L,53455L,53456L,53457L,53458L,53459L,53460L,53461L,53462L,
8505553463L,53464L,53465L,53466L,53467L,53468L,53469L,53470L,53471L,53472L,
8505653473L,53474L,53475L,53476L,53477L,53478L,53479L,53480L,53481L,53482L,
8505753483L,53484L,53485L,53486L,53487L,53488L,53489L,53490L,53491L,53492L,
8505853493L,53494L,53495L,53496L,53497L,53498L,53499L,53500L,53501L,53502L,
8505953503L,53504L,53505L,53506L,53507L,53508L,53509L,53510L,53511L,53512L,
8506053513L,53514L,53515L,53516L,53517L,53518L,53519L,53520L,53521L,53522L,
8506153523L,53524L,53525L,53526L,53527L,53528L,53529L,53530L,53531L,53532L,
8506253533L,53534L,53535L,53536L,53537L,53538L,53539L,53540L,53541L,53542L,
8506353543L,53544L,53545L,53546L,53547L,53548L,53549L,53550L,53551L,53552L,
8506453553L,53554L,53555L,53556L,53557L,53558L,53559L,53560L,53561L,53562L,
8506553563L,53564L,53565L,53566L,53567L,53568L,53569L,53570L,53571L,53572L,
8506653573L,53574L,53575L,53576L,53577L,53578L,53579L,53580L,53581L,53582L,
8506753583L,53584L,53585L,53586L,53587L,53588L,53589L,53590L,53591L,53592L,
8506853593L,53594L,53595L,53596L,53597L,53598L,53599L,53600L,53601L,53602L,
8506953603L,53604L,53605L,53606L,53607L,53608L,53609L,53610L,53611L,53612L,
8507053613L,53614L,53615L,53616L,53617L,53618L,53619L,53620L,53621L,53622L,
8507153623L,53624L,53625L,53626L,53627L,53628L,53629L,53630L,53631L,53632L,
8507253633L,53634L,53635L,53636L,53637L,53638L,53639L,53640L,53641L,53642L,
8507353643L,53644L,53645L,53646L,53647L,53648L,53649L,53650L,53651L,53652L,
8507453653L,53654L,53655L,53656L,53657L,53658L,53659L,53660L,53661L,53662L,
8507553663L,53664L,53665L,53666L,53667L,53668L,53669L,53670L,53671L,53672L,
8507653673L,53674L,53675L,53676L,53677L,53678L,53679L,53680L,53681L,53682L,
8507753683L,53684L,53685L,53686L,53687L,53688L,53689L,53690L,53691L,53692L,
8507853693L,53694L,53695L,53696L,53697L,53698L,53699L,53700L,53701L,53702L,
8507953703L,53704L,53705L,53706L,53707L,53708L,53709L,53710L,53711L,53712L,
8508053713L,53714L,53715L,53716L,53717L,53718L,53719L,53720L,53721L,53722L,
8508153723L,53724L,53725L,53726L,53727L,53728L,53729L,53730L,53731L,53732L,
8508253733L,53734L,53735L,53736L,53737L,53738L,53739L,53740L,53741L,53742L,
8508353743L,53744L,53745L,53746L,53747L,53748L,53749L,53750L,53751L,53752L,
8508453753L,53754L,53755L,53756L,53757L,53758L,53759L,53760L,53761L,53762L,
8508553763L,53764L,53765L,53766L,53767L,53768L,53769L,53770L,53771L,53772L,
8508653773L,53774L,53775L,53776L,53777L,53778L,53779L,53780L,53781L,53782L,
8508753783L,53784L,53785L,53786L,53787L,53788L,53789L,53790L,53791L,53792L,
8508853793L,53794L,53795L,53796L,53797L,53798L,53799L,53800L,53801L,53802L,
8508953803L,53804L,53805L,53806L,53807L,53808L,53809L,53810L,53811L,53812L,
8509053813L,53814L,53815L,53816L,53817L,53818L,53819L,53820L,53821L,53822L,
8509153823L,53824L,53825L,53826L,53827L,53828L,53829L,53830L,53831L,53832L,
8509253833L,53834L,53835L,53836L,53837L,53838L,53839L,53840L,53841L,53842L,
8509353843L,53844L,53845L,53846L,53847L,53848L,53849L,53850L,53851L,53852L,
8509453853L,53854L,53855L,53856L,53857L,53858L,53859L,53860L,53861L,53862L,
8509553863L,53864L,53865L,53866L,53867L,53868L,53869L,53870L,53871L,53872L,
8509653873L,53874L,53875L,53876L,53877L,53878L,53879L,53880L,53881L,53882L,
8509753883L,53884L,53885L,53886L,53887L,53888L,53889L,53890L,53891L,53892L,
8509853893L,53894L,53895L,53896L,53897L,53898L,53899L,53900L,53901L,53902L,
8509953903L,53904L,53905L,53906L,53907L,53908L,53909L,53910L,53911L,53912L,
8510053913L,53914L,53915L,53916L,53917L,53918L,53919L,53920L,53921L,53922L,
8510153923L,53924L,53925L,53926L,53927L,53928L,53929L,53930L,53931L,53932L,
8510253933L,53934L,53935L,53936L,53937L,53938L,53939L,53940L,53941L,53942L,
8510353943L,53944L,53945L,53946L,53947L,53948L,53949L,53950L,53951L,53952L,
8510453953L,53954L,53955L,53956L,53957L,53958L,53959L,53960L,53961L,53962L,
8510553963L,53964L,53965L,53966L,53967L,53968L,53969L,53970L,53971L,53972L,
8510653973L,53974L,53975L,53976L,53977L,53978L,53979L,53980L,53981L,53982L,
8510753983L,53984L,53985L,53986L,53987L,53988L,53989L,53990L,53991L,53992L,
8510853993L,53994L,53995L,53996L,53997L,53998L,53999L,54000L,54001L,54002L,
8510954003L,54004L,54005L,54006L,54007L,54008L,54009L,54010L,54011L,54012L,
8511054013L,54014L,54015L,54016L,54017L,54018L,54019L,54020L,54021L,54022L,
8511154023L,54024L,54025L,54026L,54027L,54028L,54029L,54030L,54031L,54032L,
8511254033L,54034L,54035L,54036L,54037L,54038L,54039L,54040L,54041L,54042L,
8511354043L,54044L,54045L,54046L,54047L,54048L,54049L,54050L,54051L,54052L,
8511454053L,54054L,54055L,54056L,54057L,54058L,54059L,54060L,54061L,54062L,
8511554063L,54064L,54065L,54066L,54067L,54068L,54069L,54070L,54071L,54072L,
8511654073L,54074L,54075L,54076L,54077L,54078L,54079L,54080L,54081L,54082L,
8511754083L,54084L,54085L,54086L,54087L,54088L,54089L,54090L,54091L,54092L,
8511854093L,54094L,54095L,54096L,54097L,54098L,54099L,54100L,54101L,54102L,
8511954103L,54104L,54105L,54106L,54107L,54108L,54109L,54110L,54111L,54112L,
8512054113L,54114L,54115L,54116L,54117L,54118L,54119L,54120L,54121L,54122L,
8512154123L,54124L,54125L,54126L,54127L,54128L,54129L,54130L,54131L,54132L,
8512254133L,54134L,54135L,54136L,54137L,54138L,54139L,54140L,54141L,54142L,
8512354143L,54144L,54145L,54146L,54147L,54148L,54149L,54150L,54151L,54152L,
8512454153L,54154L,54155L,54156L,54157L,54158L,54159L,54160L,54161L,54162L,
8512554163L,54164L,54165L,54166L,54167L,54168L,54169L,54170L,54171L,54172L,
8512654173L,54174L,54175L,54176L,54177L,54178L,54179L,54180L,54181L,54182L,
8512754183L,54184L,54185L,54186L,54187L,54188L,54189L,54190L,54191L,54192L,
8512854193L,54194L,54195L,54196L,54197L,54198L,54199L,54200L,54201L,54202L,
8512954203L,54204L,54205L,54206L,54207L,54208L,54209L,54210L,54211L,54212L,
8513054213L,54214L,54215L,54216L,54217L,54218L,54219L,54220L,54221L,54222L,
8513154223L,54224L,54225L,54226L,54227L,54228L,54229L,54230L,54231L,54232L,
8513254233L,54234L,54235L,54236L,54237L,54238L,54239L,54240L,54241L,54242L,
8513354243L,54244L,54245L,54246L,54247L,54248L,54249L,54250L,54251L,54252L,
8513454253L,54254L,54255L,54256L,54257L,54258L,54259L,54260L,54261L,54262L,
8513554263L,54264L,54265L,54266L,54267L,54268L,54269L,54270L,54271L,54272L,
8513654273L,54274L,54275L,54276L,54277L,54278L,54279L,54280L,54281L,54282L,
8513754283L,54284L,54285L,54286L,54287L,54288L,54289L,54290L,54291L,54292L,
8513854293L,54294L,54295L,54296L,54297L,54298L,54299L,54300L,54301L,54302L,
8513954303L,54304L,54305L,54306L,54307L,54308L,54309L,54310L,54311L,54312L,
8514054313L,54314L,54315L,54316L,54317L,54318L,54319L,54320L,54321L,54322L,
8514154323L,54324L,54325L,54326L,54327L,54328L,54329L,54330L,54331L,54332L,
8514254333L,54334L,54335L,54336L,54337L,54338L,54339L,54340L,54341L,54342L,
8514354343L,54344L,54345L,54346L,54347L,54348L,54349L,54350L,54351L,54352L,
8514454353L,54354L,54355L,54356L,54357L,54358L,54359L,54360L,54361L,54362L,
8514554363L,54364L,54365L,54366L,54367L,54368L,54369L,54370L,54371L,54372L,
8514654373L,54374L,54375L,54376L,54377L,54378L,54379L,54380L,54381L,54382L,
8514754383L,54384L,54385L,54386L,54387L,54388L,54389L,54390L,54391L,54392L,
8514854393L,54394L,54395L,54396L,54397L,54398L,54399L,54400L,54401L,54402L,
8514954403L,54404L,54405L,54406L,54407L,54408L,54409L,54410L,54411L,54412L,
8515054413L,54414L,54415L,54416L,54417L,54418L,54419L,54420L,54421L,54422L,
8515154423L,54424L,54425L,54426L,54427L,54428L,54429L,54430L,54431L,54432L,
8515254433L,54434L,54435L,54436L,54437L,54438L,54439L,54440L,54441L,54442L,
8515354443L,54444L,54445L,54446L,54447L,54448L,54449L,54450L,54451L,54452L,
8515454453L,54454L,54455L,54456L,54457L,54458L,54459L,54460L,54461L,54462L,
8515554463L,54464L,54465L,54466L,54467L,54468L,54469L,54470L,54471L,54472L,
8515654473L,54474L,54475L,54476L,54477L,54478L,54479L,54480L,54481L,54482L,
8515754483L,54484L,54485L,54486L,54487L,54488L,54489L,54490L,54491L,54492L,
8515854493L,54494L,54495L,54496L,54497L,54498L,54499L,54500L,54501L,54502L,
8515954503L,54504L,54505L,54506L,54507L,54508L,54509L,54510L,54511L,54512L,
8516054513L,54514L,54515L,54516L,54517L,54518L,54519L,54520L,54521L,54522L,
8516154523L,54524L,54525L,54526L,54527L,54528L,54529L,54530L,54531L,54532L,
8516254533L,54534L,54535L,54536L,54537L,54538L,54539L,54540L,54541L,54542L,
8516354543L,54544L,54545L,54546L,54547L,54548L,54549L,54550L,54551L,54552L,
8516454553L,54554L,54555L,54556L,54557L,54558L,54559L,54560L,54561L,54562L,
8516554563L,54564L,54565L,54566L,54567L,54568L,54569L,54570L,54571L,54572L,
8516654573L,54574L,54575L,54576L,54577L,54578L,54579L,54580L,54581L,54582L,
8516754583L,54584L,54585L,54586L,54587L,54588L,54589L,54590L,54591L,54592L,
8516854593L,54594L,54595L,54596L,54597L,54598L,54599L,54600L,54601L,54602L,
8516954603L,54604L,54605L,54606L,54607L,54608L,54609L,54610L,54611L,54612L,
8517054613L,54614L,54615L,54616L,54617L,54618L,54619L,54620L,54621L,54622L,
8517154623L,54624L,54625L,54626L,54627L,54628L,54629L,54630L,54631L,54632L,
8517254633L,54634L,54635L,54636L,54637L,54638L,54639L,54640L,54641L,54642L,
8517354643L,54644L,54645L,54646L,54647L,54648L,54649L,54650L,54651L,54652L,
8517454653L,54654L,54655L,54656L,54657L,54658L,54659L,54660L,54661L,54662L,
8517554663L,54664L,54665L,54666L,54667L,54668L,54669L,54670L,54671L,54672L,
8517654673L,54674L,54675L,54676L,54677L,54678L,54679L,54680L,54681L,54682L,
8517754683L,54684L,54685L,54686L,54687L,54688L,54689L,54690L,54691L,54692L,
8517854693L,54694L,54695L,54696L,54697L,54698L,54699L,54700L,54701L,54702L,
8517954703L,54704L,54705L,54706L,54707L,54708L,54709L,54710L,54711L,54712L,
8518054713L,54714L,54715L,54716L,54717L,54718L,54719L,54720L,54721L,54722L,
8518154723L,54724L,54725L,54726L,54727L,54728L,54729L,54730L,54731L,54732L,
8518254733L,54734L,54735L,54736L,54737L,54738L,54739L,54740L,54741L,54742L,
8518354743L,54744L,54745L,54746L,54747L,54748L,54749L,54750L,54751L,54752L,
8518454753L,54754L,54755L,54756L,54757L,54758L,54759L,54760L,54761L,54762L,
8518554763L,54764L,54765L,54766L,54767L,54768L,54769L,54770L,54771L,54772L,
8518654773L,54774L,54775L,54776L,54777L,54778L,54779L,54780L,54781L,54782L,
8518754783L,54784L,54785L,54786L,54787L,54788L,54789L,54790L,54791L,54792L,
8518854793L,54794L,54795L,54796L,54797L,54798L,54799L,54800L,54801L,54802L,
8518954803L,54804L,54805L,54806L,54807L,54808L,54809L,54810L,54811L,54812L,
8519054813L,54814L,54815L,54816L,54817L,54818L,54819L,54820L,54821L,54822L,
8519154823L,54824L,54825L,54826L,54827L,54828L,54829L,54830L,54831L,54832L,
8519254833L,54834L,54835L,54836L,54837L,54838L,54839L,54840L,54841L,54842L,
8519354843L,54844L,54845L,54846L,54847L,54848L,54849L,54850L,54851L,54852L,
8519454853L,54854L,54855L,54856L,54857L,54858L,54859L,54860L,54861L,54862L,
8519554863L,54864L,54865L,54866L,54867L,54868L,54869L,54870L,54871L,54872L,
8519654873L,54874L,54875L,54876L,54877L,54878L,54879L,54880L,54881L,54882L,
8519754883L,54884L,54885L,54886L,54887L,54888L,54889L,54890L,54891L,54892L,
8519854893L,54894L,54895L,54896L,54897L,54898L,54899L,54900L,54901L,54902L,
8519954903L,54904L,54905L,54906L,54907L,54908L,54909L,54910L,54911L,54912L,
8520054913L,54914L,54915L,54916L,54917L,54918L,54919L,54920L,54921L,54922L,
8520154923L,54924L,54925L,54926L,54927L,54928L,54929L,54930L,54931L,54932L,
8520254933L,54934L,54935L,54936L,54937L,54938L,54939L,54940L,54941L,54942L,
8520354943L,54944L,54945L,54946L,54947L,54948L,54949L,54950L,54951L,54952L,
8520454953L,54954L,54955L,54956L,54957L,54958L,54959L,54960L,54961L,54962L,
8520554963L,54964L,54965L,54966L,54967L,54968L,54969L,54970L,54971L,54972L,
8520654973L,54974L,54975L,54976L,54977L,54978L,54979L,54980L,54981L,54982L,
8520754983L,54984L,54985L,54986L,54987L,54988L,54989L,54990L,54991L,54992L,
8520854993L,54994L,54995L,54996L,54997L,54998L,54999L,55000L,55001L,55002L,
8520955003L,55004L,55005L,55006L,55007L,55008L,55009L,55010L,55011L,55012L,
8521055013L,55014L,55015L,55016L,55017L,55018L,55019L,55020L,55021L,55022L,
8521155023L,55024L,55025L,55026L,55027L,55028L,55029L,55030L,55031L,55032L,
8521255033L,55034L,55035L,55036L,55037L,55038L,55039L,55040L,55041L,55042L,
8521355043L,55044L,55045L,55046L,55047L,55048L,55049L,55050L,55051L,55052L,
8521455053L,55054L,55055L,55056L,55057L,55058L,55059L,55060L,55061L,55062L,
8521555063L,55064L,55065L,55066L,55067L,55068L,55069L,55070L,55071L,55072L,
8521655073L,55074L,55075L,55076L,55077L,55078L,55079L,55080L,55081L,55082L,
8521755083L,55084L,55085L,55086L,55087L,55088L,55089L,55090L,55091L,55092L,
8521855093L,55094L,55095L,55096L,55097L,55098L,55099L,55100L,55101L,55102L,
8521955103L,55104L,55105L,55106L,55107L,55108L,55109L,55110L,55111L,55112L,
8522055113L,55114L,55115L,55116L,55117L,55118L,55119L,55120L,55121L,55122L,
8522155123L,55124L,55125L,55126L,55127L,55128L,55129L,55130L,55131L,55132L,
8522255133L,55134L,55135L,55136L,55137L,55138L,55139L,55140L,55141L,55142L,
8522355143L,55144L,55145L,55146L,55147L,55148L,55149L,55150L,55151L,55152L,
8522455153L,55154L,55155L,55156L,55157L,55158L,55159L,55160L,55161L,55162L,
8522555163L,55164L,55165L,55166L,55167L,55168L,55169L,55170L,55171L,55172L,
8522655173L,55174L,55175L,55176L,55177L,55178L,55179L,55180L,55181L,55182L,
8522755183L,55184L,55185L,55186L,55187L,55188L,55189L,55190L,55191L,55192L,
8522855193L,55194L,55195L,55196L,55197L,55198L,55199L,55200L,55201L,55202L,
8522955203L,55204L,55205L,55206L,55207L,55208L,55209L,55210L,55211L,55212L,
8523055213L,55214L,55215L,55216L,55217L,55218L,55219L,55220L,55221L,55222L,
8523155223L,55224L,55225L,55226L,55227L,55228L,55229L,55230L,55231L,55232L,
8523255233L,55234L,55235L,55236L,55237L,55238L,55239L,55240L,55241L,55242L,
8523355243L,55244L,55245L,55246L,55247L,55248L,55249L,55250L,55251L,55252L,
8523455253L,55254L,55255L,55256L,55257L,55258L,55259L,55260L,55261L,55262L,
8523555263L,55264L,55265L,55266L,55267L,55268L,55269L,55270L,55271L,55272L,
8523655273L,55274L,55275L,55276L,55277L,55278L,55279L,55280L,55281L,55282L,
8523755283L,55284L,55285L,55286L,55287L,55288L,55289L,55290L,55291L,55292L,
8523855293L,55294L,55295L,55296L,55297L,55298L,55299L,55300L,55301L,55302L,
8523955303L,55304L,55305L,55306L,55307L,55308L,55309L,55310L,55311L,55312L,
8524055313L,55314L,55315L,55316L,55317L,55318L,55319L,55320L,55321L,55322L,
8524155323L,55324L,55325L,55326L,55327L,55328L,55329L,55330L,55331L,55332L,
8524255333L,55334L,55335L,55336L,55337L,55338L,55339L,55340L,55341L,55342L,
8524355343L,55344L,55345L,55346L,55347L,55348L,55349L,55350L,55351L,55352L,
8524455353L,55354L,55355L,55356L,55357L,55358L,55359L,55360L,55361L,55362L,
8524555363L,55364L,55365L,55366L,55367L,55368L,55369L,55370L,55371L,55372L,
8524655373L,55374L,55375L,55376L,55377L,55378L,55379L,55380L,55381L,55382L,
8524755383L,55384L,55385L,55386L,55387L,55388L,55389L,55390L,55391L,55392L,
8524855393L,55394L,55395L,55396L,55397L,55398L,55399L,55400L,55401L,55402L,
8524955403L,55404L,55405L,55406L,55407L,55408L,55409L,55410L,55411L,55412L,
8525055413L,55414L,55415L,55416L,55417L,55418L,55419L,55420L,55421L,55422L,
8525155423L,55424L,55425L,55426L,55427L,55428L,55429L,55430L,55431L,55432L,
8525255433L,55434L,55435L,55436L,55437L,55438L,55439L,55440L,55441L,55442L,
8525355443L,55444L,55445L,55446L,55447L,55448L,55449L,55450L,55451L,55452L,
8525455453L,55454L,55455L,55456L,55457L,55458L,55459L,55460L,55461L,55462L,
8525555463L,55464L,55465L,55466L,55467L,55468L,55469L,55470L,55471L,55472L,
8525655473L,55474L,55475L,55476L,55477L,55478L,55479L,55480L,55481L,55482L,
8525755483L,55484L,55485L,55486L,55487L,55488L,55489L,55490L,55491L,55492L,
8525855493L,55494L,55495L,55496L,55497L,55498L,55499L,55500L,55501L,55502L,
8525955503L,55504L,55505L,55506L,55507L,55508L,55509L,55510L,55511L,55512L,
8526055513L,55514L,55515L,55516L,55517L,55518L,55519L,55520L,55521L,55522L,
8526155523L,55524L,55525L,55526L,55527L,55528L,55529L,55530L,55531L,55532L,
8526255533L,55534L,55535L,55536L,55537L,55538L,55539L,55540L,55541L,55542L,
8526355543L,55544L,55545L,55546L,55547L,55548L,55549L,55550L,55551L,55552L,
8526455553L,55554L,55555L,55556L,55557L,55558L,55559L,55560L,55561L,55562L,
8526555563L,55564L,55565L,55566L,55567L,55568L,55569L,55570L,55571L,55572L,
8526655573L,55574L,55575L,55576L,55577L,55578L,55579L,55580L,55581L,55582L,
8526755583L,55584L,55585L,55586L,55587L,55588L,55589L,55590L,55591L,55592L,
8526855593L,55594L,55595L,55596L,55597L,55598L,55599L,55600L,55601L,55602L,
8526955603L,55604L,55605L,55606L,55607L,55608L,55609L,55610L,55611L,55612L,
8527055613L,55614L,55615L,55616L,55617L,55618L,55619L,55620L,55621L,55622L,
8527155623L,55624L,55625L,55626L,55627L,55628L,55629L,55630L,55631L,55632L,
8527255633L,55634L,55635L,55636L,55637L,55638L,55639L,55640L,55641L,55642L,
8527355643L,55644L,55645L,55646L,55647L,55648L,55649L,55650L,55651L,55652L,
8527455653L,55654L,55655L,55656L,55657L,55658L,55659L,55660L,55661L,55662L,
8527555663L,55664L,55665L,55666L,55667L,55668L,55669L,55670L,55671L,55672L,
8527655673L,55674L,55675L,55676L,55677L,55678L,55679L,55680L,55681L,55682L,
8527755683L,55684L,55685L,55686L,55687L,55688L,55689L,55690L,55691L,55692L,
8527855693L,55694L,55695L,55696L,55697L,55698L,55699L,55700L,55701L,55702L,
8527955703L,55704L,55705L,55706L,55707L,55708L,55709L,55710L,55711L,55712L,
8528055713L,55714L,55715L,55716L,55717L,55718L,55719L,55720L,55721L,55722L,
8528155723L,55724L,55725L,55726L,55727L,55728L,55729L,55730L,55731L,55732L,
8528255733L,55734L,55735L,55736L,55737L,55738L,55739L,55740L,55741L,55742L,
8528355743L,55744L,55745L,55746L,55747L,55748L,55749L,55750L,55751L,55752L,
8528455753L,55754L,55755L,55756L,55757L,55758L,55759L,55760L,55761L,55762L,
8528555763L,55764L,55765L,55766L,55767L,55768L,55769L,55770L,55771L,55772L,
8528655773L,55774L,55775L,55776L,55777L,55778L,55779L,55780L,55781L,55782L,
8528755783L,55784L,55785L,55786L,55787L,55788L,55789L,55790L,55791L,55792L,
8528855793L,55794L,55795L,55796L,55797L,55798L,55799L,55800L,55801L,55802L,
8528955803L,55804L,55805L,55806L,55807L,55808L,55809L,55810L,55811L,55812L,
8529055813L,55814L,55815L,55816L,55817L,55818L,55819L,55820L,55821L,55822L,
8529155823L,55824L,55825L,55826L,55827L,55828L,55829L,55830L,55831L,55832L,
8529255833L,55834L,55835L,55836L,55837L,55838L,55839L,55840L,55841L,55842L,
8529355843L,55844L,55845L,55846L,55847L,55848L,55849L,55850L,55851L,55852L,
8529455853L,55854L,55855L,55856L,55857L,55858L,55859L,55860L,55861L,55862L,
8529555863L,55864L,55865L,55866L,55867L,55868L,55869L,55870L,55871L,55872L,
8529655873L,55874L,55875L,55876L,55877L,55878L,55879L,55880L,55881L,55882L,
8529755883L,55884L,55885L,55886L,55887L,55888L,55889L,55890L,55891L,55892L,
8529855893L,55894L,55895L,55896L,55897L,55898L,55899L,55900L,55901L,55902L,
8529955903L,55904L,55905L,55906L,55907L,55908L,55909L,55910L,55911L,55912L,
8530055913L,55914L,55915L,55916L,55917L,55918L,55919L,55920L,55921L,55922L,
8530155923L,55924L,55925L,55926L,55927L,55928L,55929L,55930L,55931L,55932L,
8530255933L,55934L,55935L,55936L,55937L,55938L,55939L,55940L,55941L,55942L,
8530355943L,55944L,55945L,55946L,55947L,55948L,55949L,55950L,55951L,55952L,
8530455953L,55954L,55955L,55956L,55957L,55958L,55959L,55960L,55961L,55962L,
8530555963L,55964L,55965L,55966L,55967L,55968L,55969L,55970L,55971L,55972L,
8530655973L,55974L,55975L,55976L,55977L,55978L,55979L,55980L,55981L,55982L,
8530755983L,55984L,55985L,55986L,55987L,55988L,55989L,55990L,55991L,55992L,
8530855993L,55994L,55995L,55996L,55997L,55998L,55999L,56000L,56001L,56002L,
8530956003L,56004L,56005L,56006L,56007L,56008L,56009L,56010L,56011L,56012L,
8531056013L,56014L,56015L,56016L,56017L,56018L,56019L,56020L,56021L,56022L,
8531156023L,56024L,56025L,56026L,56027L,56028L,56029L,56030L,56031L,56032L,
8531256033L,56034L,56035L,56036L,56037L,56038L,56039L,56040L,56041L,56042L,
8531356043L,56044L,56045L,56046L,56047L,56048L,56049L,56050L,56051L,56052L,
8531456053L,56054L,56055L,56056L,56057L,56058L,56059L,56060L,56061L,56062L,
8531556063L,56064L,56065L,56066L,56067L,56068L,56069L,56070L,56071L,56072L,
8531656073L,56074L,56075L,56076L,56077L,56078L,56079L,56080L,56081L,56082L,
8531756083L,56084L,56085L,56086L,56087L,56088L,56089L,56090L,56091L,56092L,
8531856093L,56094L,56095L,56096L,56097L,56098L,56099L,56100L,56101L,56102L,
8531956103L,56104L,56105L,56106L,56107L,56108L,56109L,56110L,56111L,56112L,
8532056113L,56114L,56115L,56116L,56117L,56118L,56119L,56120L,56121L,56122L,
8532156123L,56124L,56125L,56126L,56127L,56128L,56129L,56130L,56131L,56132L,
8532256133L,56134L,56135L,56136L,56137L,56138L,56139L,56140L,56141L,56142L,
8532356143L,56144L,56145L,56146L,56147L,56148L,56149L,56150L,56151L,56152L,
8532456153L,56154L,56155L,56156L,56157L,56158L,56159L,56160L,56161L,56162L,
8532556163L,56164L,56165L,56166L,56167L,56168L,56169L,56170L,56171L,56172L,
8532656173L,56174L,56175L,56176L,56177L,56178L,56179L,56180L,56181L,56182L,
8532756183L,56184L,56185L,56186L,56187L,56188L,56189L,56190L,56191L,56192L,
8532856193L,56194L,56195L,56196L,56197L,56198L,56199L,56200L,56201L,56202L,
8532956203L,56204L,56205L,56206L,56207L,56208L,56209L,56210L,56211L,56212L,
8533056213L,56214L,56215L,56216L,56217L,56218L,56219L,56220L,56221L,56222L,
8533156223L,56224L,56225L,56226L,56227L,56228L,56229L,56230L,56231L,56232L,
8533256233L,56234L,56235L,56236L,56237L,56238L,56239L,56240L,56241L,56242L,
8533356243L,56244L,56245L,56246L,56247L,56248L,56249L,56250L,56251L,56252L,
8533456253L,56254L,56255L,56256L,56257L,56258L,56259L,56260L,56261L,56262L,
8533556263L,56264L,56265L,56266L,56267L,56268L,56269L,56270L,56271L,56272L,
8533656273L,56274L,56275L,56276L,56277L,56278L,56279L,56280L,56281L,56282L,
8533756283L,56284L,56285L,56286L,56287L,56288L,56289L,56290L,56291L,56292L,
8533856293L,56294L,56295L,56296L,56297L,56298L,56299L,56300L,56301L,56302L,
8533956303L,56304L,56305L,56306L,56307L,56308L,56309L,56310L,56311L,56312L,
8534056313L,56314L,56315L,56316L,56317L,56318L,56319L,56320L,56321L,56322L,
8534156323L,56324L,56325L,56326L,56327L,56328L,56329L,56330L,56331L,56332L,
8534256333L,56334L,56335L,56336L,56337L,56338L,56339L,56340L,56341L,56342L,
8534356343L,56344L,56345L,56346L,56347L,56348L,56349L,56350L,56351L,56352L,
8534456353L,56354L,56355L,56356L,56357L,56358L,56359L,56360L,56361L,56362L,
8534556363L,56364L,56365L,56366L,56367L,56368L,56369L,56370L,56371L,56372L,
8534656373L,56374L,56375L,56376L,56377L,56378L,56379L,56380L,56381L,56382L,
8534756383L,56384L,56385L,56386L,56387L,56388L,56389L,56390L,56391L,56392L,
8534856393L,56394L,56395L,56396L,56397L,56398L,56399L,56400L,56401L,56402L,
8534956403L,56404L,56405L,56406L,56407L,56408L,56409L,56410L,56411L,56412L,
8535056413L,56414L,56415L,56416L,56417L,56418L,56419L,56420L,56421L,56422L,
8535156423L,56424L,56425L,56426L,56427L,56428L,56429L,56430L,56431L,56432L,
8535256433L,56434L,56435L,56436L,56437L,56438L,56439L,56440L,56441L,56442L,
8535356443L,56444L,56445L,56446L,56447L,56448L,56449L,56450L,56451L,56452L,
8535456453L,56454L,56455L,56456L,56457L,56458L,56459L,56460L,56461L,56462L,
8535556463L,56464L,56465L,56466L,56467L,56468L,56469L,56470L,56471L,56472L,
8535656473L,56474L,56475L,56476L,56477L,56478L,56479L,56480L,56481L,56482L,
8535756483L,56484L,56485L,56486L,56487L,56488L,56489L,56490L,56491L,56492L,
8535856493L,56494L,56495L,56496L,56497L,56498L,56499L,56500L,56501L,56502L,
8535956503L,56504L,56505L,56506L,56507L,56508L,56509L,56510L,56511L,56512L,
8536056513L,56514L,56515L,56516L,56517L,56518L,56519L,56520L,56521L,56522L,
8536156523L,56524L,56525L,56526L,56527L,56528L,56529L,56530L,56531L,56532L,
8536256533L,56534L,56535L,56536L,56537L,56538L,56539L,56540L,56541L,56542L,
8536356543L,56544L,56545L,56546L,56547L,56548L,56549L,56550L,56551L,56552L,
8536456553L,56554L,56555L,56556L,56557L,56558L,56559L,56560L,56561L,56562L,
8536556563L,56564L,56565L,56566L,56567L,56568L,56569L,56570L,56571L,56572L,
8536656573L,56574L,56575L,56576L,56577L,56578L,56579L,56580L,56581L,56582L,
8536756583L,56584L,56585L,56586L,56587L,56588L,56589L,56590L,56591L,56592L,
8536856593L,56594L,56595L,56596L,56597L,56598L,56599L,56600L,56601L,56602L,
8536956603L,56604L,56605L,56606L,56607L,56608L,56609L,56610L,56611L,56612L,
8537056613L,56614L,56615L,56616L,56617L,56618L,56619L,56620L,56621L,56622L,
8537156623L,56624L,56625L,56626L,56627L,56628L,56629L,56630L,56631L,56632L,
8537256633L,56634L,56635L,56636L,56637L,56638L,56639L,56640L,56641L,56642L,
8537356643L,56644L,56645L,56646L,56647L,56648L,56649L,56650L,56651L,56652L,
8537456653L,56654L,56655L,56656L,56657L,56658L,56659L,56660L,56661L,56662L,
8537556663L,56664L,56665L,56666L,56667L,56668L,56669L,56670L,56671L,56672L,
8537656673L,56674L,56675L,56676L,56677L,56678L,56679L,56680L,56681L,56682L,
8537756683L,56684L,56685L,56686L,56687L,56688L,56689L,56690L,56691L,56692L,
8537856693L,56694L,56695L,56696L,56697L,56698L,56699L,56700L,56701L,56702L,
8537956703L,56704L,56705L,56706L,56707L,56708L,56709L,56710L,56711L,56712L,
8538056713L,56714L,56715L,56716L,56717L,56718L,56719L,56720L,56721L,56722L,
8538156723L,56724L,56725L,56726L,56727L,56728L,56729L,56730L,56731L,56732L,
8538256733L,56734L,56735L,56736L,56737L,56738L,56739L,56740L,56741L,56742L,
8538356743L,56744L,56745L,56746L,56747L,56748L,56749L,56750L,56751L,56752L,
8538456753L,56754L,56755L,56756L,56757L,56758L,56759L,56760L,56761L,56762L,
8538556763L,56764L,56765L,56766L,56767L,56768L,56769L,56770L,56771L,56772L,
8538656773L,56774L,56775L,56776L,56777L,56778L,56779L,56780L,56781L,56782L,
8538756783L,56784L,56785L,56786L,56787L,56788L,56789L,56790L,56791L,56792L,
8538856793L,56794L,56795L,56796L,56797L,56798L,56799L,56800L,56801L,56802L,
8538956803L,56804L,56805L,56806L,56807L,56808L,56809L,56810L,56811L,56812L,
8539056813L,56814L,56815L,56816L,56817L,56818L,56819L,56820L,56821L,56822L,
8539156823L,56824L,56825L,56826L,56827L,56828L,56829L,56830L,56831L,56832L,
8539256833L,56834L,56835L,56836L,56837L,56838L,56839L,56840L,56841L,56842L,
8539356843L,56844L,56845L,56846L,56847L,56848L,56849L,56850L,56851L,56852L,
8539456853L,56854L,56855L,56856L,56857L,56858L,56859L,56860L,56861L,56862L,
8539556863L,56864L,56865L,56866L,56867L,56868L,56869L,56870L,56871L,56872L,
8539656873L,56874L,56875L,56876L,56877L,56878L,56879L,56880L,56881L,56882L,
8539756883L,56884L,56885L,56886L,56887L,56888L,56889L,56890L,56891L,56892L,
8539856893L,56894L,56895L,56896L,56897L,56898L,56899L,56900L,56901L,56902L,
8539956903L,56904L,56905L,56906L,56907L,56908L,56909L,56910L,56911L,56912L,
8540056913L,56914L,56915L,56916L,56917L,56918L,56919L,56920L,56921L,56922L,
8540156923L,56924L,56925L,56926L,56927L,56928L,56929L,56930L,56931L,56932L,
8540256933L,56934L,56935L,56936L,56937L,56938L,56939L,56940L,56941L,56942L,
8540356943L,56944L,56945L,56946L,56947L,56948L,56949L,56950L,56951L,56952L,
8540456953L,56954L,56955L,56956L,56957L,56958L,56959L,56960L,56961L,56962L,
8540556963L,56964L,56965L,56966L,56967L,56968L,56969L,56970L,56971L,56972L,
8540656973L,56974L,56975L,56976L,56977L,56978L,56979L,56980L,56981L,56982L,
8540756983L,56984L,56985L,56986L,56987L,56988L,56989L,56990L,56991L,56992L,
8540856993L,56994L,56995L,56996L,56997L,56998L,56999L,57000L,57001L,57002L,
8540957003L,57004L,57005L,57006L,57007L,57008L,57009L,57010L,57011L,57012L,
8541057013L,57014L,57015L,57016L,57017L,57018L,57019L,57020L,57021L,57022L,
8541157023L,57024L,57025L,57026L,57027L,57028L,57029L,57030L,57031L,57032L,
8541257033L,57034L,57035L,57036L,57037L,57038L,57039L,57040L,57041L,57042L,
8541357043L,57044L,57045L,57046L,57047L,57048L,57049L,57050L,57051L,57052L,
8541457053L,57054L,57055L,57056L,57057L,57058L,57059L,57060L,57061L,57062L,
8541557063L,57064L,57065L,57066L,57067L,57068L,57069L,57070L,57071L,57072L,
8541657073L,57074L,57075L,57076L,57077L,57078L,57079L,57080L,57081L,57082L,
8541757083L,57084L,57085L,57086L,57087L,57088L,57089L,57090L,57091L,57092L,
8541857093L,57094L,57095L,57096L,57097L,57098L,57099L,57100L,57101L,57102L,
8541957103L,57104L,57105L,57106L,57107L,57108L,57109L,57110L,57111L,57112L,
8542057113L,57114L,57115L,57116L,57117L,57118L,57119L,57120L,57121L,57122L,
8542157123L,57124L,57125L,57126L,57127L,57128L,57129L,57130L,57131L,57132L,
8542257133L,57134L,57135L,57136L,57137L,57138L,57139L,57140L,57141L,57142L,
8542357143L,57144L,57145L,57146L,57147L,57148L,57149L,57150L,57151L,57152L,
8542457153L,57154L,57155L,57156L,57157L,57158L,57159L,57160L,57161L,57162L,
8542557163L,57164L,57165L,57166L,57167L,57168L,57169L,57170L,57171L,57172L,
8542657173L,57174L,57175L,57176L,57177L,57178L,57179L,57180L,57181L,57182L,
8542757183L,57184L,57185L,57186L,57187L,57188L,57189L,57190L,57191L,57192L,
8542857193L,57194L,57195L,57196L,57197L,57198L,57199L,57200L,57201L,57202L,
8542957203L,57204L,57205L,57206L,57207L,57208L,57209L,57210L,57211L,57212L,
8543057213L,57214L,57215L,57216L,57217L,57218L,57219L,57220L,57221L,57222L,
8543157223L,57224L,57225L,57226L,57227L,57228L,57229L,57230L,57231L,57232L,
8543257233L,57234L,57235L,57236L,57237L,57238L,57239L,57240L,57241L,57242L,
8543357243L,57244L,57245L,57246L,57247L,57248L,57249L,57250L,57251L,57252L,
8543457253L,57254L,57255L,57256L,57257L,57258L,57259L,57260L,57261L,57262L,
8543557263L,57264L,57265L,57266L,57267L,57268L,57269L,57270L,57271L,57272L,
8543657273L,57274L,57275L,57276L,57277L,57278L,57279L,57280L,57281L,57282L,
8543757283L,57284L,57285L,57286L,57287L,57288L,57289L,57290L,57291L,57292L,
8543857293L,57294L,57295L,57296L,57297L,57298L,57299L,57300L,57301L,57302L,
8543957303L,57304L,57305L,57306L,57307L,57308L,57309L,57310L,57311L,57312L,
8544057313L,57314L,57315L,57316L,57317L,57318L,57319L,57320L,57321L,57322L,
8544157323L,57324L,57325L,57326L,57327L,57328L,57329L,57330L,57331L,57332L,
8544257333L,57334L,57335L,57336L,57337L,57338L,57339L,57340L,57341L,57342L,
8544357343L,57344L,57345L,57346L,57347L,57348L,57349L,57350L,57351L,57352L,
8544457353L,57354L,57355L,57356L,57357L,57358L,57359L,57360L,57361L,57362L,
8544557363L,57364L,57365L,57366L,57367L,57368L,57369L,57370L,57371L,57372L,
8544657373L,57374L,57375L,57376L,57377L,57378L,57379L,57380L,57381L,57382L,
8544757383L,57384L,57385L,57386L,57387L,57388L,57389L,57390L,57391L,57392L,
8544857393L,57394L,57395L,57396L,57397L,57398L,57399L,57400L,57401L,57402L,
8544957403L,57404L,57405L,57406L,57407L,57408L,57409L,57410L,57411L,57412L,
8545057413L,57414L,57415L,57416L,57417L,57418L,57419L,57420L,57421L,57422L,
8545157423L,57424L,57425L,57426L,57427L,57428L,57429L,57430L,57431L,57432L,
8545257433L,57434L,57435L,57436L,57437L,57438L,57439L,57440L,57441L,57442L,
8545357443L,57444L,57445L,57446L,57447L,57448L,57449L,57450L,57451L,57452L,
8545457453L,57454L,57455L,57456L,57457L,57458L,57459L,57460L,57461L,57462L,
8545557463L,57464L,57465L,57466L,57467L,57468L,57469L,57470L,57471L,57472L,
8545657473L,57474L,57475L,57476L,57477L,57478L,57479L,57480L,57481L,57482L,
8545757483L,57484L,57485L,57486L,57487L,57488L,57489L,57490L,57491L,57492L,
8545857493L,57494L,57495L,57496L,57497L,57498L,57499L,57500L,57501L,57502L,
8545957503L,57504L,57505L,57506L,57507L,57508L,57509L,57510L,57511L,57512L,
8546057513L,57514L,57515L,57516L,57517L,57518L,57519L,57520L,57521L,57522L,
8546157523L,57524L,57525L,57526L,57527L,57528L,57529L,57530L,57531L,57532L,
8546257533L,57534L,57535L,57536L,57537L,57538L,57539L,57540L,57541L,57542L,
8546357543L,57544L,57545L,57546L,57547L,57548L,57549L,57550L,57551L,57552L,
8546457553L,57554L,57555L,57556L,57557L,57558L,57559L,57560L,57561L,57562L,
8546557563L,57564L,57565L,57566L,57567L,57568L,57569L,57570L,57571L,57572L,
8546657573L,57574L,57575L,57576L,57577L,57578L,57579L,57580L,57581L,57582L,
8546757583L,57584L,57585L,57586L,57587L,57588L,57589L,57590L,57591L,57592L,
8546857593L,57594L,57595L,57596L,57597L,57598L,57599L,57600L,57601L,57602L,
8546957603L,57604L,57605L,57606L,57607L,57608L,57609L,57610L,57611L,57612L,
8547057613L,57614L,57615L,57616L,57617L,57618L,57619L,57620L,57621L,57622L,
8547157623L,57624L,57625L,57626L,57627L,57628L,57629L,57630L,57631L,57632L,
8547257633L,57634L,57635L,57636L,57637L,57638L,57639L,57640L,57641L,57642L,
8547357643L,57644L,57645L,57646L,57647L,57648L,57649L,57650L,57651L,57652L,
8547457653L,57654L,57655L,57656L,57657L,57658L,57659L,57660L,57661L,57662L,
8547557663L,57664L,57665L,57666L,57667L,57668L,57669L,57670L,57671L,57672L,
8547657673L,57674L,57675L,57676L,57677L,57678L,57679L,57680L,57681L,57682L,
8547757683L,57684L,57685L,57686L,57687L,57688L,57689L,57690L,57691L,57692L,
8547857693L,57694L,57695L,57696L,57697L,57698L,57699L,57700L,57701L,57702L,
8547957703L,57704L,57705L,57706L,57707L,57708L,57709L,57710L,57711L,57712L,
8548057713L,57714L,57715L,57716L,57717L,57718L,57719L,57720L,57721L,57722L,
8548157723L,57724L,57725L,57726L,57727L,57728L,57729L,57730L,57731L,57732L,
8548257733L,57734L,57735L,57736L,57737L,57738L,57739L,57740L,57741L,57742L,
8548357743L,57744L,57745L,57746L,57747L,57748L,57749L,57750L,57751L,57752L,
8548457753L,57754L,57755L,57756L,57757L,57758L,57759L,57760L,57761L,57762L,
8548557763L,57764L,57765L,57766L,57767L,57768L,57769L,57770L,57771L,57772L,
8548657773L,57774L,57775L,57776L,57777L,57778L,57779L,57780L,57781L,57782L,
8548757783L,57784L,57785L,57786L,57787L,57788L,57789L,57790L,57791L,57792L,
8548857793L,57794L,57795L,57796L,57797L,57798L,57799L,57800L,57801L,57802L,
8548957803L,57804L,57805L,57806L,57807L,57808L,57809L,57810L,57811L,57812L,
8549057813L,57814L,57815L,57816L,57817L,57818L,57819L,57820L,57821L,57822L,
8549157823L,57824L,57825L,57826L,57827L,57828L,57829L,57830L,57831L,57832L,
8549257833L,57834L,57835L,57836L,57837L,57838L,57839L,57840L,57841L,57842L,
8549357843L,57844L,57845L,57846L,57847L,57848L,57849L,57850L,57851L,57852L,
8549457853L,57854L,57855L,57856L,57857L,57858L,57859L,57860L,57861L,57862L,
8549557863L,57864L,57865L,57866L,57867L,57868L,57869L,57870L,57871L,57872L,
8549657873L,57874L,57875L,57876L,57877L,57878L,57879L,57880L,57881L,57882L,
8549757883L,57884L,57885L,57886L,57887L,57888L,57889L,57890L,57891L,57892L,
8549857893L,57894L,57895L,57896L,57897L,57898L,57899L,57900L,57901L,57902L,
8549957903L,57904L,57905L,57906L,57907L,57908L,57909L,57910L,57911L,57912L,
8550057913L,57914L,57915L,57916L,57917L,57918L,57919L,57920L,57921L,57922L,
8550157923L,57924L,57925L,57926L,57927L,57928L,57929L,57930L,57931L,57932L,
8550257933L,57934L,57935L,57936L,57937L,57938L,57939L,57940L,57941L,57942L,
8550357943L,57944L,57945L,57946L,57947L,57948L,57949L,57950L,57951L,57952L,
8550457953L,57954L,57955L,57956L,57957L,57958L,57959L,57960L,57961L,57962L,
8550557963L,57964L,57965L,57966L,57967L,57968L,57969L,57970L,57971L,57972L,
8550657973L,57974L,57975L,57976L,57977L,57978L,57979L,57980L,57981L,57982L,
8550757983L,57984L,57985L,57986L,57987L,57988L,57989L,57990L,57991L,57992L,
8550857993L,57994L,57995L,57996L,57997L,57998L,57999L,58000L,58001L,58002L,
8550958003L,58004L,58005L,58006L,58007L,58008L,58009L,58010L,58011L,58012L,
8551058013L,58014L,58015L,58016L,58017L,58018L,58019L,58020L,58021L,58022L,
8551158023L,58024L,58025L,58026L,58027L,58028L,58029L,58030L,58031L,58032L,
8551258033L,58034L,58035L,58036L,58037L,58038L,58039L,58040L,58041L,58042L,
8551358043L,58044L,58045L,58046L,58047L,58048L,58049L,58050L,58051L,58052L,
8551458053L,58054L,58055L,58056L,58057L,58058L,58059L,58060L,58061L,58062L,
8551558063L,58064L,58065L,58066L,58067L,58068L,58069L,58070L,58071L,58072L,
8551658073L,58074L,58075L,58076L,58077L,58078L,58079L,58080L,58081L,58082L,
8551758083L,58084L,58085L,58086L,58087L,58088L,58089L,58090L,58091L,58092L,
8551858093L,58094L,58095L,58096L,58097L,58098L,58099L,58100L,58101L,58102L,
8551958103L,58104L,58105L,58106L,58107L,58108L,58109L,58110L,58111L,58112L,
8552058113L,58114L,58115L,58116L,58117L,58118L,58119L,58120L,58121L,58122L,
8552158123L,58124L,58125L,58126L,58127L,58128L,58129L,58130L,58131L,58132L,
8552258133L,58134L,58135L,58136L,58137L,58138L,58139L,58140L,58141L,58142L,
8552358143L,58144L,58145L,58146L,58147L,58148L,58149L,58150L,58151L,58152L,
8552458153L,58154L,58155L,58156L,58157L,58158L,58159L,58160L,58161L,58162L,
8552558163L,58164L,58165L,58166L,58167L,58168L,58169L,58170L,58171L,58172L,
8552658173L,58174L,58175L,58176L,58177L,58178L,58179L,58180L,58181L,58182L,
8552758183L,58184L,58185L,58186L,58187L,58188L,58189L,58190L,58191L,58192L,
8552858193L,58194L,58195L,58196L,58197L,58198L,58199L,58200L,58201L,58202L,
8552958203L,58204L,58205L,58206L,58207L,58208L,58209L,58210L,58211L,58212L,
8553058213L,58214L,58215L,58216L,58217L,58218L,58219L,58220L,58221L,58222L,
8553158223L,58224L,58225L,58226L,58227L,58228L,58229L,58230L,58231L,58232L,
8553258233L,58234L,58235L,58236L,58237L,58238L,58239L,58240L,58241L,58242L,
8553358243L,58244L,58245L,58246L,58247L,58248L,58249L,58250L,58251L,58252L,
8553458253L,58254L,58255L,58256L,58257L,58258L,58259L,58260L,58261L,58262L,
8553558263L,58264L,58265L,58266L,58267L,58268L,58269L,58270L,58271L,58272L,
8553658273L,58274L,58275L,58276L,58277L,58278L,58279L,58280L,58281L,58282L,
8553758283L,58284L,58285L,58286L,58287L,58288L,58289L,58290L,58291L,58292L,
8553858293L,58294L,58295L,58296L,58297L,58298L,58299L,58300L,58301L,58302L,
8553958303L,58304L,58305L,58306L,58307L,58308L,58309L,58310L,58311L,58312L,
8554058313L,58314L,58315L,58316L,58317L,58318L,58319L,58320L,58321L,58322L,
8554158323L,58324L,58325L,58326L,58327L,58328L,58329L,58330L,58331L,58332L,
8554258333L,58334L,58335L,58336L,58337L,58338L,58339L,58340L,58341L,58342L,
8554358343L,58344L,58345L,58346L,58347L,58348L,58349L,58350L,58351L,58352L,
8554458353L,58354L,58355L,58356L,58357L,58358L,58359L,58360L,58361L,58362L,
8554558363L,58364L,58365L,58366L,58367L,58368L,58369L,58370L,58371L,58372L,
8554658373L,58374L,58375L,58376L,58377L,58378L,58379L,58380L,58381L,58382L,
8554758383L,58384L,58385L,58386L,58387L,58388L,58389L,58390L,58391L,58392L,
8554858393L,58394L,58395L,58396L,58397L,58398L,58399L,58400L,58401L,58402L,
8554958403L,58404L,58405L,58406L,58407L,58408L,58409L,58410L,58411L,58412L,
8555058413L,58414L,58415L,58416L,58417L,58418L,58419L,58420L,58421L,58422L,
8555158423L,58424L,58425L,58426L,58427L,58428L,58429L,58430L,58431L,58432L,
8555258433L,58434L,58435L,58436L,58437L,58438L,58439L,58440L,58441L,58442L,
8555358443L,58444L,58445L,58446L,58447L,58448L,58449L,58450L,58451L,58452L,
8555458453L,58454L,58455L,58456L,58457L,58458L,58459L,58460L,58461L,58462L,
8555558463L,58464L,58465L,58466L,58467L,58468L,58469L,58470L,58471L,58472L,
8555658473L,58474L,58475L,58476L,58477L,58478L,58479L,58480L,58481L,58482L,
8555758483L,58484L,58485L,58486L,58487L,58488L,58489L,58490L,58491L,58492L,
8555858493L,58494L,58495L,58496L,58497L,58498L,58499L,58500L,58501L,58502L,
8555958503L,58504L,58505L,58506L,58507L,58508L,58509L,58510L,58511L,58512L,
8556058513L,58514L,58515L,58516L,58517L,58518L,58519L,58520L,58521L,58522L,
8556158523L,58524L,58525L,58526L,58527L,58528L,58529L,58530L,58531L,58532L,
8556258533L,58534L,58535L,58536L,58537L,58538L,58539L,58540L,58541L,58542L,
8556358543L,58544L,58545L,58546L,58547L,58548L,58549L,58550L,58551L,58552L,
8556458553L,58554L,58555L,58556L,58557L,58558L,58559L,58560L,58561L,58562L,
8556558563L,58564L,58565L,58566L,58567L,58568L,58569L,58570L,58571L,58572L,
8556658573L,58574L,58575L,58576L,58577L,58578L,58579L,58580L,58581L,58582L,
8556758583L,58584L,58585L,58586L,58587L,58588L,58589L,58590L,58591L,58592L,
8556858593L,58594L,58595L,58596L,58597L,58598L,58599L,58600L,58601L,58602L,
8556958603L,58604L,58605L,58606L,58607L,58608L,58609L,58610L,58611L,58612L,
8557058613L,58614L,58615L,58616L,58617L,58618L,58619L,58620L,58621L,58622L,
8557158623L,58624L,58625L,58626L,58627L,58628L,58629L,58630L,58631L,58632L,
8557258633L,58634L,58635L,58636L,58637L,58638L,58639L,58640L,58641L,58642L,
8557358643L,58644L,58645L,58646L,58647L,58648L,58649L,58650L,58651L,58652L,
8557458653L,58654L,58655L,58656L,58657L,58658L,58659L,58660L,58661L,58662L,
8557558663L,58664L,58665L,58666L,58667L,58668L,58669L,58670L,58671L,58672L,
8557658673L,58674L,58675L,58676L,58677L,58678L,58679L,58680L,58681L,58682L,
8557758683L,58684L,58685L,58686L,58687L,58688L,58689L,58690L,58691L,58692L,
8557858693L,58694L,58695L,58696L,58697L,58698L,58699L,58700L,58701L,58702L,
8557958703L,58704L,58705L,58706L,58707L,58708L,58709L,58710L,58711L,58712L,
8558058713L,58714L,58715L,58716L,58717L,58718L,58719L,58720L,58721L,58722L,
8558158723L,58724L,58725L,58726L,58727L,58728L,58729L,58730L,58731L,58732L,
8558258733L,58734L,58735L,58736L,58737L,58738L,58739L,58740L,58741L,58742L,
8558358743L,58744L,58745L,58746L,58747L,58748L,58749L,58750L,58751L,58752L,
8558458753L,58754L,58755L,58756L,58757L,58758L,58759L,58760L,58761L,58762L,
8558558763L,58764L,58765L,58766L,58767L,58768L,58769L,58770L,58771L,58772L,
8558658773L,58774L,58775L,58776L,58777L,58778L,58779L,58780L,58781L,58782L,
8558758783L,58784L,58785L,58786L,58787L,58788L,58789L,58790L,58791L,58792L,
8558858793L,58794L,58795L,58796L,58797L,58798L,58799L,58800L,58801L,58802L,
8558958803L,58804L,58805L,58806L,58807L,58808L,58809L,58810L,58811L,58812L,
8559058813L,58814L,58815L,58816L,58817L,58818L,58819L,58820L,58821L,58822L,
8559158823L,58824L,58825L,58826L,58827L,58828L,58829L,58830L,58831L,58832L,
8559258833L,58834L,58835L,58836L,58837L,58838L,58839L,58840L,58841L,58842L,
8559358843L,58844L,58845L,58846L,58847L,58848L,58849L,58850L,58851L,58852L,
8559458853L,58854L,58855L,58856L,58857L,58858L,58859L,58860L,58861L,58862L,
8559558863L,58864L,58865L,58866L,58867L,58868L,58869L,58870L,58871L,58872L,
8559658873L,58874L,58875L,58876L,58877L,58878L,58879L,58880L,58881L,58882L,
8559758883L,58884L,58885L,58886L,58887L,58888L,58889L,58890L,58891L,58892L,
8559858893L,58894L,58895L,58896L,58897L,58898L,58899L,58900L,58901L,58902L,
8559958903L,58904L,58905L,58906L,58907L,58908L,58909L,58910L,58911L,58912L,
8560058913L,58914L,58915L,58916L,58917L,58918L,58919L,58920L,58921L,58922L,
8560158923L,58924L,58925L,58926L,58927L,58928L,58929L,58930L,58931L,58932L,
8560258933L,58934L,58935L,58936L,58937L,58938L,58939L,58940L,58941L,58942L,
8560358943L,58944L,58945L,58946L,58947L,58948L,58949L,58950L,58951L,58952L,
8560458953L,58954L,58955L,58956L,58957L,58958L,58959L,58960L,58961L,58962L,
8560558963L,58964L,58965L,58966L,58967L,58968L,58969L,58970L,58971L,58972L,
8560658973L,58974L,58975L,58976L,58977L,58978L,58979L,58980L,58981L,58982L,
8560758983L,58984L,58985L,58986L,58987L,58988L,58989L,58990L,58991L,58992L,
8560858993L,58994L,58995L,58996L,58997L,58998L,58999L,59000L,59001L,59002L,
8560959003L,59004L,59005L,59006L,59007L,59008L,59009L,59010L,59011L,59012L,
8561059013L,59014L,59015L,59016L,59017L,59018L,59019L,59020L,59021L,59022L,
8561159023L,59024L,59025L,59026L,59027L,59028L,59029L,59030L,59031L,59032L,
8561259033L,59034L,59035L,59036L,59037L,59038L,59039L,59040L,59041L,59042L,
8561359043L,59044L,59045L,59046L,59047L,59048L,59049L,59050L,59051L,59052L,
8561459053L,59054L,59055L,59056L,59057L,59058L,59059L,59060L,59061L,59062L,
8561559063L,59064L,59065L,59066L,59067L,59068L,59069L,59070L,59071L,59072L,
8561659073L,59074L,59075L,59076L,59077L,59078L,59079L,59080L,59081L,59082L,
8561759083L,59084L,59085L,59086L,59087L,59088L,59089L,59090L,59091L,59092L,
8561859093L,59094L,59095L,59096L,59097L,59098L,59099L,59100L,59101L,59102L,
8561959103L,59104L,59105L,59106L,59107L,59108L,59109L,59110L,59111L,59112L,
8562059113L,59114L,59115L,59116L,59117L,59118L,59119L,59120L,59121L,59122L,
8562159123L,59124L,59125L,59126L,59127L,59128L,59129L,59130L,59131L,59132L,
8562259133L,59134L,59135L,59136L,59137L,59138L,59139L,59140L,59141L,59142L,
8562359143L,59144L,59145L,59146L,59147L,59148L,59149L,59150L,59151L,59152L,
8562459153L,59154L,59155L,59156L,59157L,59158L,59159L,59160L,59161L,59162L,
8562559163L,59164L,59165L,59166L,59167L,59168L,59169L,59170L,59171L,59172L,
8562659173L,59174L,59175L,59176L,59177L,59178L,59179L,59180L,59181L,59182L,
8562759183L,59184L,59185L,59186L,59187L,59188L,59189L,59190L,59191L,59192L,
8562859193L,59194L,59195L,59196L,59197L,59198L,59199L,59200L,59201L,59202L,
8562959203L,59204L,59205L,59206L,59207L,59208L,59209L,59210L,59211L,59212L,
8563059213L,59214L,59215L,59216L,59217L,59218L,59219L,59220L,59221L,59222L,
8563159223L,59224L,59225L,59226L,59227L,59228L,59229L,59230L,59231L,59232L,
8563259233L,59234L,59235L,59236L,59237L,59238L,59239L,59240L,59241L,59242L,
8563359243L,59244L,59245L,59246L,59247L,59248L,59249L,59250L,59251L,59252L,
8563459253L,59254L,59255L,59256L,59257L,59258L,59259L,59260L,59261L,59262L,
8563559263L,59264L,59265L,59266L,59267L,59268L,59269L,59270L,59271L,59272L,
8563659273L,59274L,59275L,59276L,59277L,59278L,59279L,59280L,59281L,59282L,
8563759283L,59284L,59285L,59286L,59287L,59288L,59289L,59290L,59291L,59292L,
8563859293L,59294L,59295L,59296L,59297L,59298L,59299L,59300L,59301L,59302L,
8563959303L,59304L,59305L,59306L,59307L,59308L,59309L,59310L,59311L,59312L,
8564059313L,59314L,59315L,59316L,59317L,59318L,59319L,59320L,59321L,59322L,
8564159323L,59324L,59325L,59326L,59327L,59328L,59329L,59330L,59331L,59332L,
8564259333L,59334L,59335L,59336L,59337L,59338L,59339L,59340L,59341L,59342L,
8564359343L,59344L,59345L,59346L,59347L,59348L,59349L,59350L,59351L,59352L,
8564459353L,59354L,59355L,59356L,59357L,59358L,59359L,59360L,59361L,59362L,
8564559363L,59364L,59365L,59366L,59367L,59368L,59369L,59370L,59371L,59372L,
8564659373L,59374L,59375L,59376L,59377L,59378L,59379L,59380L,59381L,59382L,
8564759383L,59384L,59385L,59386L,59387L,59388L,59389L,59390L,59391L,59392L,
8564859393L,59394L,59395L,59396L,59397L,59398L,59399L,59400L,59401L,59402L,
8564959403L,59404L,59405L,59406L,59407L,59408L,59409L,59410L,59411L,59412L,
8565059413L,59414L,59415L,59416L,59417L,59418L,59419L,59420L,59421L,59422L,
8565159423L,59424L,59425L,59426L,59427L,59428L,59429L,59430L,59431L,59432L,
8565259433L,59434L,59435L,59436L,59437L,59438L,59439L,59440L,59441L,59442L,
8565359443L,59444L,59445L,59446L,59447L,59448L,59449L,59450L,59451L,59452L,
8565459453L,59454L,59455L,59456L,59457L,59458L,59459L,59460L,59461L,59462L,
8565559463L,59464L,59465L,59466L,59467L,59468L,59469L,59470L,59471L,59472L,
8565659473L,59474L,59475L,59476L,59477L,59478L,59479L,59480L,59481L,59482L,
8565759483L,59484L,59485L,59486L,59487L,59488L,59489L,59490L,59491L,59492L,
8565859493L,59494L,59495L,59496L,59497L,59498L,59499L,59500L,59501L,59502L,
8565959503L,59504L,59505L,59506L,59507L,59508L,59509L,59510L,59511L,59512L,
8566059513L,59514L,59515L,59516L,59517L,59518L,59519L,59520L,59521L,59522L,
8566159523L,59524L,59525L,59526L,59527L,59528L,59529L,59530L,59531L,59532L,
8566259533L,59534L,59535L,59536L,59537L,59538L,59539L,59540L,59541L,59542L,
8566359543L,59544L,59545L,59546L,59547L,59548L,59549L,59550L,59551L,59552L,
8566459553L,59554L,59555L,59556L,59557L,59558L,59559L,59560L,59561L,59562L,
8566559563L,59564L,59565L,59566L,59567L,59568L,59569L,59570L,59571L,59572L,
8566659573L,59574L,59575L,59576L,59577L,59578L,59579L,59580L,59581L,59582L,
8566759583L,59584L,59585L,59586L,59587L,59588L,59589L,59590L,59591L,59592L,
8566859593L,59594L,59595L,59596L,59597L,59598L,59599L,59600L,59601L,59602L,
8566959603L,59604L,59605L,59606L,59607L,59608L,59609L,59610L,59611L,59612L,
8567059613L,59614L,59615L,59616L,59617L,59618L,59619L,59620L,59621L,59622L,
8567159623L,59624L,59625L,59626L,59627L,59628L,59629L,59630L,59631L,59632L,
8567259633L,59634L,59635L,59636L,59637L,59638L,59639L,59640L,59641L,59642L,
8567359643L,59644L,59645L,59646L,59647L,59648L,59649L,59650L,59651L,59652L,
8567459653L,59654L,59655L,59656L,59657L,59658L,59659L,59660L,59661L,59662L,
8567559663L,59664L,59665L,59666L,59667L,59668L,59669L,59670L,59671L,59672L,
8567659673L,59674L,59675L,59676L,59677L,59678L,59679L,59680L,59681L,59682L,
8567759683L,59684L,59685L,59686L,59687L,59688L,59689L,59690L,59691L,59692L,
8567859693L,59694L,59695L,59696L,59697L,59698L,59699L,59700L,59701L,59702L,
8567959703L,59704L,59705L,59706L,59707L,59708L,59709L,59710L,59711L,59712L,
8568059713L,59714L,59715L,59716L,59717L,59718L,59719L,59720L,59721L,59722L,
8568159723L,59724L,59725L,59726L,59727L,59728L,59729L,59730L,59731L,59732L,
8568259733L,59734L,59735L,59736L,59737L,59738L,59739L,59740L,59741L,59742L,
8568359743L,59744L,59745L,59746L,59747L,59748L,59749L,59750L,59751L,59752L,
8568459753L,59754L,59755L,59756L,59757L,59758L,59759L,59760L,59761L,59762L,
8568559763L,59764L,59765L,59766L,59767L,59768L,59769L,59770L,59771L,59772L,
8568659773L,59774L,59775L,59776L,59777L,59778L,59779L,59780L,59781L,59782L,
8568759783L,59784L,59785L,59786L,59787L,59788L,59789L,59790L,59791L,59792L,
8568859793L,59794L,59795L,59796L,59797L,59798L,59799L,59800L,59801L,59802L,
8568959803L,59804L,59805L,59806L,59807L,59808L,59809L,59810L,59811L,59812L,
8569059813L,59814L,59815L,59816L,59817L,59818L,59819L,59820L,59821L,59822L,
8569159823L,59824L,59825L,59826L,59827L,59828L,59829L,59830L,59831L,59832L,
8569259833L,59834L,59835L,59836L,59837L,59838L,59839L,59840L,59841L,59842L,
8569359843L,59844L,59845L,59846L,59847L,59848L,59849L,59850L,59851L,59852L,
8569459853L,59854L,59855L,59856L,59857L,59858L,59859L,59860L,59861L,59862L,
8569559863L,59864L,59865L,59866L,59867L,59868L,59869L,59870L,59871L,59872L,
8569659873L,59874L,59875L,59876L,59877L,59878L,59879L,59880L,59881L,59882L,
8569759883L,59884L,59885L,59886L,59887L,59888L,59889L,59890L,59891L,59892L,
8569859893L,59894L,59895L,59896L,59897L,59898L,59899L,59900L,59901L,59902L,
8569959903L,59904L,59905L,59906L,59907L,59908L,59909L,59910L,59911L,59912L,
8570059913L,59914L,59915L,59916L,59917L,59918L,59919L,59920L,59921L,59922L,
8570159923L,59924L,59925L,59926L,59927L,59928L,59929L,59930L,59931L,59932L,
8570259933L,59934L,59935L,59936L,59937L,59938L,59939L,59940L,59941L,59942L,
8570359943L,59944L,59945L,59946L,59947L,59948L,59949L,59950L,59951L,59952L,
8570459953L,59954L,59955L,59956L,59957L,59958L,59959L,59960L,59961L,59962L,
8570559963L,59964L,59965L,59966L,59967L,59968L,59969L,59970L,59971L,59972L,
8570659973L,59974L,59975L,59976L,59977L,59978L,59979L,59980L,59981L,59982L,
8570759983L,59984L,59985L,59986L,59987L,59988L,59989L,59990L,59991L,59992L,
8570859993L,59994L,59995L,59996L,59997L,59998L,59999L,60000L,60001L,60002L,
8570960003L,60004L,60005L,60006L,60007L,60008L,60009L,60010L,60011L,60012L,
8571060013L,60014L,60015L,60016L,60017L,60018L,60019L,60020L,60021L,60022L,
8571160023L,60024L,60025L,60026L,60027L,60028L,60029L,60030L,60031L,60032L,
8571260033L,60034L,60035L,60036L,60037L,60038L,60039L,60040L,60041L,60042L,
8571360043L,60044L,60045L,60046L,60047L,60048L,60049L,60050L,60051L,60052L,
8571460053L,60054L,60055L,60056L,60057L,60058L,60059L,60060L,60061L,60062L,
8571560063L,60064L,60065L,60066L,60067L,60068L,60069L,60070L,60071L,60072L,
8571660073L,60074L,60075L,60076L,60077L,60078L,60079L,60080L,60081L,60082L,
8571760083L,60084L,60085L,60086L,60087L,60088L,60089L,60090L,60091L,60092L,
8571860093L,60094L,60095L,60096L,60097L,60098L,60099L,60100L,60101L,60102L,
8571960103L,60104L,60105L,60106L,60107L,60108L,60109L,60110L,60111L,60112L,
8572060113L,60114L,60115L,60116L,60117L,60118L,60119L,60120L,60121L,60122L,
8572160123L,60124L,60125L,60126L,60127L,60128L,60129L,60130L,60131L,60132L,
8572260133L,60134L,60135L,60136L,60137L,60138L,60139L,60140L,60141L,60142L,
8572360143L,60144L,60145L,60146L,60147L,60148L,60149L,60150L,60151L,60152L,
8572460153L,60154L,60155L,60156L,60157L,60158L,60159L,60160L,60161L,60162L,
8572560163L,60164L,60165L,60166L,60167L,60168L,60169L,60170L,60171L,60172L,
8572660173L,60174L,60175L,60176L,60177L,60178L,60179L,60180L,60181L,60182L,
8572760183L,60184L,60185L,60186L,60187L,60188L,60189L,60190L,60191L,60192L,
8572860193L,60194L,60195L,60196L,60197L,60198L,60199L,60200L,60201L,60202L,
8572960203L,60204L,60205L,60206L,60207L,60208L,60209L,60210L,60211L,60212L,
8573060213L,60214L,60215L,60216L,60217L,60218L,60219L,60220L,60221L,60222L,
8573160223L,60224L,60225L,60226L,60227L,60228L,60229L,60230L,60231L,60232L,
8573260233L,60234L,60235L,60236L,60237L,60238L,60239L,60240L,60241L,60242L,
8573360243L,60244L,60245L,60246L,60247L,60248L,60249L,60250L,60251L,60252L,
8573460253L,60254L,60255L,60256L,60257L,60258L,60259L,60260L,60261L,60262L,
8573560263L,60264L,60265L,60266L,60267L,60268L,60269L,60270L,60271L,60272L,
8573660273L,60274L,60275L,60276L,60277L,60278L,60279L,60280L,60281L,60282L,
8573760283L,60284L,60285L,60286L,60287L,60288L,60289L,60290L,60291L,60292L,
8573860293L,60294L,60295L,60296L,60297L,60298L,60299L,60300L,60301L,60302L,
8573960303L,60304L,60305L,60306L,60307L,60308L,60309L,60310L,60311L,60312L,
8574060313L,60314L,60315L,60316L,60317L,60318L,60319L,60320L,60321L,60322L,
8574160323L,60324L,60325L,60326L,60327L,60328L,60329L,60330L,60331L,60332L,
8574260333L,60334L,60335L,60336L,60337L,60338L,60339L,60340L,60341L,60342L,
8574360343L,60344L,60345L,60346L,60347L,60348L,60349L,60350L,60351L,60352L,
8574460353L,60354L,60355L,60356L,60357L,60358L,60359L,60360L,60361L,60362L,
8574560363L,60364L,60365L,60366L,60367L,60368L,60369L,60370L,60371L,60372L,
8574660373L,60374L,60375L,60376L,60377L,60378L,60379L,60380L,60381L,60382L,
8574760383L,60384L,60385L,60386L,60387L,60388L,60389L,60390L,60391L,60392L,
8574860393L,60394L,60395L,60396L,60397L,60398L,60399L,60400L,60401L,60402L,
8574960403L,60404L,60405L,60406L,60407L,60408L,60409L,60410L,60411L,60412L,
8575060413L,60414L,60415L,60416L,60417L,60418L,60419L,60420L,60421L,60422L,
8575160423L,60424L,60425L,60426L,60427L,60428L,60429L,60430L,60431L,60432L,
8575260433L,60434L,60435L,60436L,60437L,60438L,60439L,60440L,60441L,60442L,
8575360443L,60444L,60445L,60446L,60447L,60448L,60449L,60450L,60451L,60452L,
8575460453L,60454L,60455L,60456L,60457L,60458L,60459L,60460L,60461L,60462L,
8575560463L,60464L,60465L,60466L,60467L,60468L,60469L,60470L,60471L,60472L,
8575660473L,60474L,60475L,60476L,60477L,60478L,60479L,60480L,60481L,60482L,
8575760483L,60484L,60485L,60486L,60487L,60488L,60489L,60490L,60491L,60492L,
8575860493L,60494L,60495L,60496L,60497L,60498L,60499L,60500L,60501L,60502L,
8575960503L,60504L,60505L,60506L,60507L,60508L,60509L,60510L,60511L,60512L,
8576060513L,60514L,60515L,60516L,60517L,60518L,60519L,60520L,60521L,60522L,
8576160523L,60524L,60525L,60526L,60527L,60528L,60529L,60530L,60531L,60532L,
8576260533L,60534L,60535L,60536L,60537L,60538L,60539L,60540L,60541L,60542L,
8576360543L,60544L,60545L,60546L,60547L,60548L,60549L,60550L,60551L,60552L,
8576460553L,60554L,60555L,60556L,60557L,60558L,60559L,60560L,60561L,60562L,
8576560563L,60564L,60565L,60566L,60567L,60568L,60569L,60570L,60571L,60572L,
8576660573L,60574L,60575L,60576L,60577L,60578L,60579L,60580L,60581L,60582L,
8576760583L,60584L,60585L,60586L,60587L,60588L,60589L,60590L,60591L,60592L,
8576860593L,60594L,60595L,60596L,60597L,60598L,60599L,60600L,60601L,60602L,
8576960603L,60604L,60605L,60606L,60607L,60608L,60609L,60610L,60611L,60612L,
8577060613L,60614L,60615L,60616L,60617L,60618L,60619L,60620L,60621L,60622L,
8577160623L,60624L,60625L,60626L,60627L,60628L,60629L,60630L,60631L,60632L,
8577260633L,60634L,60635L,60636L,60637L,60638L,60639L,60640L,60641L,60642L,
8577360643L,60644L,60645L,60646L,60647L,60648L,60649L,60650L,60651L,60652L,
8577460653L,60654L,60655L,60656L,60657L,60658L,60659L,60660L,60661L,60662L,
8577560663L,60664L,60665L,60666L,60667L,60668L,60669L,60670L,60671L,60672L,
8577660673L,60674L,60675L,60676L,60677L,60678L,60679L,60680L,60681L,60682L,
8577760683L,60684L,60685L,60686L,60687L,60688L,60689L,60690L,60691L,60692L,
8577860693L,60694L,60695L,60696L,60697L,60698L,60699L,60700L,60701L,60702L,
8577960703L,60704L,60705L,60706L,60707L,60708L,60709L,60710L,60711L,60712L,
8578060713L,60714L,60715L,60716L,60717L,60718L,60719L,60720L,60721L,60722L,
8578160723L,60724L,60725L,60726L,60727L,60728L,60729L,60730L,60731L,60732L,
8578260733L,60734L,60735L,60736L,60737L,60738L,60739L,60740L,60741L,60742L,
8578360743L,60744L,60745L,60746L,60747L,60748L,60749L,60750L,60751L,60752L,
8578460753L,60754L,60755L,60756L,60757L,60758L,60759L,60760L,60761L,60762L,
8578560763L,60764L,60765L,60766L,60767L,60768L,60769L,60770L,60771L,60772L,
8578660773L,60774L,60775L,60776L,60777L,60778L,60779L,60780L,60781L,60782L,
8578760783L,60784L,60785L,60786L,60787L,60788L,60789L,60790L,60791L,60792L,
8578860793L,60794L,60795L,60796L,60797L,60798L,60799L,60800L,60801L,60802L,
8578960803L,60804L,60805L,60806L,60807L,60808L,60809L,60810L,60811L,60812L,
8579060813L,60814L,60815L,60816L,60817L,60818L,60819L,60820L,60821L,60822L,
8579160823L,60824L,60825L,60826L,60827L,60828L,60829L,60830L,60831L,60832L,
8579260833L,60834L,60835L,60836L,60837L,60838L,60839L,60840L,60841L,60842L,
8579360843L,60844L,60845L,60846L,60847L,60848L,60849L,60850L,60851L,60852L,
8579460853L,60854L,60855L,60856L,60857L,60858L,60859L,60860L,60861L,60862L,
8579560863L,60864L,60865L,60866L,60867L,60868L,60869L,60870L,60871L,60872L,
8579660873L,60874L,60875L,60876L,60877L,60878L,60879L,60880L,60881L,60882L,
8579760883L,60884L,60885L,60886L,60887L,60888L,60889L,60890L,60891L,60892L,
8579860893L,60894L,60895L,60896L,60897L,60898L,60899L,60900L,60901L,60902L,
8579960903L,60904L,60905L,60906L,60907L,60908L,60909L,60910L,60911L,60912L,
8580060913L,60914L,60915L,60916L,60917L,60918L,60919L,60920L,60921L,60922L,
8580160923L,60924L,60925L,60926L,60927L,60928L,60929L,60930L,60931L,60932L,
8580260933L,60934L,60935L,60936L,60937L,60938L,60939L,60940L,60941L,60942L,
8580360943L,60944L,60945L,60946L,60947L,60948L,60949L,60950L,60951L,60952L,
8580460953L,60954L,60955L,60956L,60957L,60958L,60959L,60960L,60961L,60962L,
8580560963L,60964L,60965L,60966L,60967L,60968L,60969L,60970L,60971L,60972L,
8580660973L,60974L,60975L,60976L,60977L,60978L,60979L,60980L,60981L,60982L,
8580760983L,60984L,60985L,60986L,60987L,60988L,60989L,60990L,60991L,60992L,
8580860993L,60994L,60995L,60996L,60997L,60998L,60999L,61000L,61001L,61002L,
8580961003L,61004L,61005L,61006L,61007L,61008L,61009L,61010L,61011L,61012L,
8581061013L,61014L,61015L,61016L,61017L,61018L,61019L,61020L,61021L,61022L,
8581161023L,61024L,61025L,61026L,61027L,61028L,61029L,61030L,61031L,61032L,
8581261033L,61034L,61035L,61036L,61037L,61038L,61039L,61040L,61041L,61042L,
8581361043L,61044L,61045L,61046L,61047L,61048L,61049L,61050L,61051L,61052L,
8581461053L,61054L,61055L,61056L,61057L,61058L,61059L,61060L,61061L,61062L,
8581561063L,61064L,61065L,61066L,61067L,61068L,61069L,61070L,61071L,61072L,
8581661073L,61074L,61075L,61076L,61077L,61078L,61079L,61080L,61081L,61082L,
8581761083L,61084L,61085L,61086L,61087L,61088L,61089L,61090L,61091L,61092L,
8581861093L,61094L,61095L,61096L,61097L,61098L,61099L,61100L,61101L,61102L,
8581961103L,61104L,61105L,61106L,61107L,61108L,61109L,61110L,61111L,61112L,
8582061113L,61114L,61115L,61116L,61117L,61118L,61119L,61120L,61121L,61122L,
8582161123L,61124L,61125L,61126L,61127L,61128L,61129L,61130L,61131L,61132L,
8582261133L,61134L,61135L,61136L,61137L,61138L,61139L,61140L,61141L,61142L,
8582361143L,61144L,61145L,61146L,61147L,61148L,61149L,61150L,61151L,61152L,
8582461153L,61154L,61155L,61156L,61157L,61158L,61159L,61160L,61161L,61162L,
8582561163L,61164L,61165L,61166L,61167L,61168L,61169L,61170L,61171L,61172L,
8582661173L,61174L,61175L,61176L,61177L,61178L,61179L,61180L,61181L,61182L,
8582761183L,61184L,61185L,61186L,61187L,61188L,61189L,61190L,61191L,61192L,
8582861193L,61194L,61195L,61196L,61197L,61198L,61199L,61200L,61201L,61202L,
8582961203L,61204L,61205L,61206L,61207L,61208L,61209L,61210L,61211L,61212L,
8583061213L,61214L,61215L,61216L,61217L,61218L,61219L,61220L,61221L,61222L,
8583161223L,61224L,61225L,61226L,61227L,61228L,61229L,61230L,61231L,61232L,
8583261233L,61234L,61235L,61236L,61237L,61238L,61239L,61240L,61241L,61242L,
8583361243L,61244L,61245L,61246L,61247L,61248L,61249L,61250L,61251L,61252L,
8583461253L,61254L,61255L,61256L,61257L,61258L,61259L,61260L,61261L,61262L,
8583561263L,61264L,61265L,61266L,61267L,61268L,61269L,61270L,61271L,61272L,
8583661273L,61274L,61275L,61276L,61277L,61278L,61279L,61280L,61281L,61282L,
8583761283L,61284L,61285L,61286L,61287L,61288L,61289L,61290L,61291L,61292L,
8583861293L,61294L,61295L,61296L,61297L,61298L,61299L,61300L,61301L,61302L,
8583961303L,61304L,61305L,61306L,61307L,61308L,61309L,61310L,61311L,61312L,
8584061313L,61314L,61315L,61316L,61317L,61318L,61319L,61320L,61321L,61322L,
8584161323L,61324L,61325L,61326L,61327L,61328L,61329L,61330L,61331L,61332L,
8584261333L,61334L,61335L,61336L,61337L,61338L,61339L,61340L,61341L,61342L,
8584361343L,61344L,61345L,61346L,61347L,61348L,61349L,61350L,61351L,61352L,
8584461353L,61354L,61355L,61356L,61357L,61358L,61359L,61360L,61361L,61362L,
8584561363L,61364L,61365L,61366L,61367L,61368L,61369L,61370L,61371L,61372L,
8584661373L,61374L,61375L,61376L,61377L,61378L,61379L,61380L,61381L,61382L,
8584761383L,61384L,61385L,61386L,61387L,61388L,61389L,61390L,61391L,61392L,
8584861393L,61394L,61395L,61396L,61397L,61398L,61399L,61400L,61401L,61402L,
8584961403L,61404L,61405L,61406L,61407L,61408L,61409L,61410L,61411L,61412L,
8585061413L,61414L,61415L,61416L,61417L,61418L,61419L,61420L,61421L,61422L,
8585161423L,61424L,61425L,61426L,61427L,61428L,61429L,61430L,61431L,61432L,
8585261433L,61434L,61435L,61436L,61437L,61438L,61439L,61440L,61441L,61442L,
8585361443L,61444L,61445L,61446L,61447L,61448L,61449L,61450L,61451L,61452L,
8585461453L,61454L,61455L,61456L,61457L,61458L,61459L,61460L,61461L,61462L,
8585561463L,61464L,61465L,61466L,61467L,61468L,61469L,61470L,61471L,61472L,
8585661473L,61474L,61475L,61476L,61477L,61478L,61479L,61480L,61481L,61482L,
8585761483L,61484L,61485L,61486L,61487L,61488L,61489L,61490L,61491L,61492L,
8585861493L,61494L,61495L,61496L,61497L,61498L,61499L,61500L,61501L,61502L,
8585961503L,61504L,61505L,61506L,61507L,61508L,61509L,61510L,61511L,61512L,
8586061513L,61514L,61515L,61516L,61517L,61518L,61519L,61520L,61521L,61522L,
8586161523L,61524L,61525L,61526L,61527L,61528L,61529L,61530L,61531L,61532L,
8586261533L,61534L,61535L,61536L,61537L,61538L,61539L,61540L,61541L,61542L,
8586361543L,61544L,61545L,61546L,61547L,61548L,61549L,61550L,61551L,61552L,
8586461553L,61554L,61555L,61556L,61557L,61558L,61559L,61560L,61561L,61562L,
8586561563L,61564L,61565L,61566L,61567L,61568L,61569L,61570L,61571L,61572L,
8586661573L,61574L,61575L,61576L,61577L,61578L,61579L,61580L,61581L,61582L,
8586761583L,61584L,61585L,61586L,61587L,61588L,61589L,61590L,61591L,61592L,
8586861593L,61594L,61595L,61596L,61597L,61598L,61599L,61600L,61601L,61602L,
8586961603L,61604L,61605L,61606L,61607L,61608L,61609L,61610L,61611L,61612L,
8587061613L,61614L,61615L,61616L,61617L,61618L,61619L,61620L,61621L,61622L,
8587161623L,61624L,61625L,61626L,61627L,61628L,61629L,61630L,61631L,61632L,
8587261633L,61634L,61635L,61636L,61637L,61638L,61639L,61640L,61641L,61642L,
8587361643L,61644L,61645L,61646L,61647L,61648L,61649L,61650L,61651L,61652L,
8587461653L,61654L,61655L,61656L,61657L,61658L,61659L,61660L,61661L,61662L,
8587561663L,61664L,61665L,61666L,61667L,61668L,61669L,61670L,61671L,61672L,
8587661673L,61674L,61675L,61676L,61677L,61678L,61679L,61680L,61681L,61682L,
8587761683L,61684L,61685L,61686L,61687L,61688L,61689L,61690L,61691L,61692L,
8587861693L,61694L,61695L,61696L,61697L,61698L,61699L,61700L,61701L,61702L,
8587961703L,61704L,61705L,61706L,61707L,61708L,61709L,61710L,61711L,61712L,
8588061713L,61714L,61715L,61716L,61717L,61718L,61719L,61720L,61721L,61722L,
8588161723L,61724L,61725L,61726L,61727L,61728L,61729L,61730L,61731L,61732L,
8588261733L,61734L,61735L,61736L,61737L,61738L,61739L,61740L,61741L,61742L,
8588361743L,61744L,61745L,61746L,61747L,61748L,61749L,61750L,61751L,61752L,
8588461753L,61754L,61755L,61756L,61757L,61758L,61759L,61760L,61761L,61762L,
8588561763L,61764L,61765L,61766L,61767L,61768L,61769L,61770L,61771L,61772L,
8588661773L,61774L,61775L,61776L,61777L,61778L,61779L,61780L,61781L,61782L,
8588761783L,61784L,61785L,61786L,61787L,61788L,61789L,61790L,61791L,61792L,
8588861793L,61794L,61795L,61796L,61797L,61798L,61799L,61800L,61801L,61802L,
8588961803L,61804L,61805L,61806L,61807L,61808L,61809L,61810L,61811L,61812L,
8589061813L,61814L,61815L,61816L,61817L,61818L,61819L,61820L,61821L,61822L,
8589161823L,61824L,61825L,61826L,61827L,61828L,61829L,61830L,61831L,61832L,
8589261833L,61834L,61835L,61836L,61837L,61838L,61839L,61840L,61841L,61842L,
8589361843L,61844L,61845L,61846L,61847L,61848L,61849L,61850L,61851L,61852L,
8589461853L,61854L,61855L,61856L,61857L,61858L,61859L,61860L,61861L,61862L,
8589561863L,61864L,61865L,61866L,61867L,61868L,61869L,61870L,61871L,61872L,
8589661873L,61874L,61875L,61876L,61877L,61878L,61879L,61880L,61881L,61882L,
8589761883L,61884L,61885L,61886L,61887L,61888L,61889L,61890L,61891L,61892L,
8589861893L,61894L,61895L,61896L,61897L,61898L,61899L,61900L,61901L,61902L,
8589961903L,61904L,61905L,61906L,61907L,61908L,61909L,61910L,61911L,61912L,
8590061913L,61914L,61915L,61916L,61917L,61918L,61919L,61920L,61921L,61922L,
8590161923L,61924L,61925L,61926L,61927L,61928L,61929L,61930L,61931L,61932L,
8590261933L,61934L,61935L,61936L,61937L,61938L,61939L,61940L,61941L,61942L,
8590361943L,61944L,61945L,61946L,61947L,61948L,61949L,61950L,61951L,61952L,
8590461953L,61954L,61955L,61956L,61957L,61958L,61959L,61960L,61961L,61962L,
8590561963L,61964L,61965L,61966L,61967L,61968L,61969L,61970L,61971L,61972L,
8590661973L,61974L,61975L,61976L,61977L,61978L,61979L,61980L,61981L,61982L,
8590761983L,61984L,61985L,61986L,61987L,61988L,61989L,61990L,61991L,61992L,
8590861993L,61994L,61995L,61996L,61997L,61998L,61999L,62000L,62001L,62002L,
8590962003L,62004L,62005L,62006L,62007L,62008L,62009L,62010L,62011L,62012L,
8591062013L,62014L,62015L,62016L,62017L,62018L,62019L,62020L,62021L,62022L,
8591162023L,62024L,62025L,62026L,62027L,62028L,62029L,62030L,62031L,62032L,
8591262033L,62034L,62035L,62036L,62037L,62038L,62039L,62040L,62041L,62042L,
8591362043L,62044L,62045L,62046L,62047L,62048L,62049L,62050L,62051L,62052L,
8591462053L,62054L,62055L,62056L,62057L,62058L,62059L,62060L,62061L,62062L,
8591562063L,62064L,62065L,62066L,62067L,62068L,62069L,62070L,62071L,62072L,
8591662073L,62074L,62075L,62076L,62077L,62078L,62079L,62080L,62081L,62082L,
8591762083L,62084L,62085L,62086L,62087L,62088L,62089L,62090L,62091L,62092L,
8591862093L,62094L,62095L,62096L,62097L,62098L,62099L,62100L,62101L,62102L,
8591962103L,62104L,62105L,62106L,62107L,62108L,62109L,62110L,62111L,62112L,
8592062113L,62114L,62115L,62116L,62117L,62118L,62119L,62120L,62121L,62122L,
8592162123L,62124L,62125L,62126L,62127L,62128L,62129L,62130L,62131L,62132L,
8592262133L,62134L,62135L,62136L,62137L,62138L,62139L,62140L,62141L,62142L,
8592362143L,62144L,62145L,62146L,62147L,62148L,62149L,62150L,62151L,62152L,
8592462153L,62154L,62155L,62156L,62157L,62158L,62159L,62160L,62161L,62162L,
8592562163L,62164L,62165L,62166L,62167L,62168L,62169L,62170L,62171L,62172L,
8592662173L,62174L,62175L,62176L,62177L,62178L,62179L,62180L,62181L,62182L,
8592762183L,62184L,62185L,62186L,62187L,62188L,62189L,62190L,62191L,62192L,
8592862193L,62194L,62195L,62196L,62197L,62198L,62199L,62200L,62201L,62202L,
8592962203L,62204L,62205L,62206L,62207L,62208L,62209L,62210L,62211L,62212L,
8593062213L,62214L,62215L,62216L,62217L,62218L,62219L,62220L,62221L,62222L,
8593162223L,62224L,62225L,62226L,62227L,62228L,62229L,62230L,62231L,62232L,
8593262233L,62234L,62235L,62236L,62237L,62238L,62239L,62240L,62241L,62242L,
8593362243L,62244L,62245L,62246L,62247L,62248L,62249L,62250L,62251L,62252L,
8593462253L,62254L,62255L,62256L,62257L,62258L,62259L,62260L,62261L,62262L,
8593562263L,62264L,62265L,62266L,62267L,62268L,62269L,62270L,62271L,62272L,
8593662273L,62274L,62275L,62276L,62277L,62278L,62279L,62280L,62281L,62282L,
8593762283L,62284L,62285L,62286L,62287L,62288L,62289L,62290L,62291L,62292L,
8593862293L,62294L,62295L,62296L,62297L,62298L,62299L,62300L,62301L,62302L,
8593962303L,62304L,62305L,62306L,62307L,62308L,62309L,62310L,62311L,62312L,
8594062313L,62314L,62315L,62316L,62317L,62318L,62319L,62320L,62321L,62322L,
8594162323L,62324L,62325L,62326L,62327L,62328L,62329L,62330L,62331L,62332L,
8594262333L,62334L,62335L,62336L,62337L,62338L,62339L,62340L,62341L,62342L,
8594362343L,62344L,62345L,62346L,62347L,62348L,62349L,62350L,62351L,62352L,
8594462353L,62354L,62355L,62356L,62357L,62358L,62359L,62360L,62361L,62362L,
8594562363L,62364L,62365L,62366L,62367L,62368L,62369L,62370L,62371L,62372L,
8594662373L,62374L,62375L,62376L,62377L,62378L,62379L,62380L,62381L,62382L,
8594762383L,62384L,62385L,62386L,62387L,62388L,62389L,62390L,62391L,62392L,
8594862393L,62394L,62395L,62396L,62397L,62398L,62399L,62400L,62401L,62402L,
8594962403L,62404L,62405L,62406L,62407L,62408L,62409L,62410L,62411L,62412L,
8595062413L,62414L,62415L,62416L,62417L,62418L,62419L,62420L,62421L,62422L,
8595162423L,62424L,62425L,62426L,62427L,62428L,62429L,62430L,62431L,62432L,
8595262433L,62434L,62435L,62436L,62437L,62438L,62439L,62440L,62441L,62442L,
8595362443L,62444L,62445L,62446L,62447L,62448L,62449L,62450L,62451L,62452L,
8595462453L,62454L,62455L,62456L,62457L,62458L,62459L,62460L,62461L,62462L,
8595562463L,62464L,62465L,62466L,62467L,62468L,62469L,62470L,62471L,62472L,
8595662473L,62474L,62475L,62476L,62477L,62478L,62479L,62480L,62481L,62482L,
8595762483L,62484L,62485L,62486L,62487L,62488L,62489L,62490L,62491L,62492L,
8595862493L,62494L,62495L,62496L,62497L,62498L,62499L,62500L,62501L,62502L,
8595962503L,62504L,62505L,62506L,62507L,62508L,62509L,62510L,62511L,62512L,
8596062513L,62514L,62515L,62516L,62517L,62518L,62519L,62520L,62521L,62522L,
8596162523L,62524L,62525L,62526L,62527L,62528L,62529L,62530L,62531L,62532L,
8596262533L,62534L,62535L,62536L,62537L,62538L,62539L,62540L,62541L,62542L,
8596362543L,62544L,62545L,62546L,62547L,62548L,62549L,62550L,62551L,62552L,
8596462553L,62554L,62555L,62556L,62557L,62558L,62559L,62560L,62561L,62562L,
8596562563L,62564L,62565L,62566L,62567L,62568L,62569L,62570L,62571L,62572L,
8596662573L,62574L,62575L,62576L,62577L,62578L,62579L,62580L,62581L,62582L,
8596762583L,62584L,62585L,62586L,62587L,62588L,62589L,62590L,62591L,62592L,
8596862593L,62594L,62595L,62596L,62597L,62598L,62599L,62600L,62601L,62602L,
8596962603L,62604L,62605L,62606L,62607L,62608L,62609L,62610L,62611L,62612L,
8597062613L,62614L,62615L,62616L,62617L,62618L,62619L,62620L,62621L,62622L,
8597162623L,62624L,62625L,62626L,62627L,62628L,62629L,62630L,62631L,62632L,
8597262633L,62634L,62635L,62636L,62637L,62638L,62639L,62640L,62641L,62642L,
8597362643L,62644L,62645L,62646L,62647L,62648L,62649L,62650L,62651L,62652L,
8597462653L,62654L,62655L,62656L,62657L,62658L,62659L,62660L,62661L,62662L,
8597562663L,62664L,62665L,62666L,62667L,62668L,62669L,62670L,62671L,62672L,
8597662673L,62674L,62675L,62676L,62677L,62678L,62679L,62680L,62681L,62682L,
8597762683L,62684L,62685L,62686L,62687L,62688L,62689L,62690L,62691L,62692L,
8597862693L,62694L,62695L,62696L,62697L,62698L,62699L,62700L,62701L,62702L,
8597962703L,62704L,62705L,62706L,62707L,62708L,62709L,62710L,62711L,62712L,
8598062713L,62714L,62715L,62716L,62717L,62718L,62719L,62720L,62721L,62722L,
8598162723L,62724L,62725L,62726L,62727L,62728L,62729L,62730L,62731L,62732L,
8598262733L,62734L,62735L,62736L,62737L,62738L,62739L,62740L,62741L,62742L,
8598362743L,62744L,62745L,62746L,62747L,62748L,62749L,62750L,62751L,62752L,
8598462753L,62754L,62755L,62756L,62757L,62758L,62759L,62760L,62761L,62762L,
8598562763L,62764L,62765L,62766L,62767L,62768L,62769L,62770L,62771L,62772L,
8598662773L,62774L,62775L,62776L,62777L,62778L,62779L,62780L,62781L,62782L,
8598762783L,62784L,62785L,62786L,62787L,62788L,62789L,62790L,62791L,62792L,
8598862793L,62794L,62795L,62796L,62797L,62798L,62799L,62800L,62801L,62802L,
8598962803L,62804L,62805L,62806L,62807L,62808L,62809L,62810L,62811L,62812L,
8599062813L,62814L,62815L,62816L,62817L,62818L,62819L,62820L,62821L,62822L,
8599162823L,62824L,62825L,62826L,62827L,62828L,62829L,62830L,62831L,62832L,
8599262833L,62834L,62835L,62836L,62837L,62838L,62839L,62840L,62841L,62842L,
8599362843L,62844L,62845L,62846L,62847L,62848L,62849L,62850L,62851L,62852L,
8599462853L,62854L,62855L,62856L,62857L,62858L,62859L,62860L,62861L,62862L,
8599562863L,62864L,62865L,62866L,62867L,62868L,62869L,62870L,62871L,62872L,
8599662873L,62874L,62875L,62876L,62877L,62878L,62879L,62880L,62881L,62882L,
8599762883L,62884L,62885L,62886L,62887L,62888L,62889L,62890L,62891L,62892L,
8599862893L,62894L,62895L,62896L,62897L,62898L,62899L,62900L,62901L,62902L,
8599962903L,62904L,62905L,62906L,62907L,62908L,62909L,62910L,62911L,62912L,
8600062913L,62914L,62915L,62916L,62917L,62918L,62919L,62920L,62921L,62922L,
8600162923L,62924L,62925L,62926L,62927L,62928L,62929L,62930L,62931L,62932L,
8600262933L,62934L,62935L,62936L,62937L,62938L,62939L,62940L,62941L,62942L,
8600362943L,62944L,62945L,62946L,62947L,62948L,62949L,62950L,62951L,62952L,
8600462953L,62954L,62955L,62956L,62957L,62958L,62959L,62960L,62961L,62962L,
8600562963L,62964L,62965L,62966L,62967L,62968L,62969L,62970L,62971L,62972L,
8600662973L,62974L,62975L,62976L,62977L,62978L,62979L,62980L,62981L,62982L,
8600762983L,62984L,62985L,62986L,62987L,62988L,62989L,62990L,62991L,62992L,
8600862993L,62994L,62995L,62996L,62997L,62998L,62999L,63000L,63001L,63002L,
8600963003L,63004L,63005L,63006L,63007L,63008L,63009L,63010L,63011L,63012L,
8601063013L,63014L,63015L,63016L,63017L,63018L,63019L,63020L,63021L,63022L,
8601163023L,63024L,63025L,63026L,63027L,63028L,63029L,63030L,63031L,63032L,
8601263033L,63034L,63035L,63036L,63037L,63038L,63039L,63040L,63041L,63042L,
8601363043L,63044L,63045L,63046L,63047L,63048L,63049L,63050L,63051L,63052L,
8601463053L,63054L,63055L,63056L,63057L,63058L,63059L,63060L,63061L,63062L,
8601563063L,63064L,63065L,63066L,63067L,63068L,63069L,63070L,63071L,63072L,
8601663073L,63074L,63075L,63076L,63077L,63078L,63079L,63080L,63081L,63082L,
8601763083L,63084L,63085L,63086L,63087L,63088L,63089L,63090L,63091L,63092L,
8601863093L,63094L,63095L,63096L,63097L,63098L,63099L,63100L,63101L,63102L,
8601963103L,63104L,63105L,63106L,63107L,63108L,63109L,63110L,63111L,63112L,
8602063113L,63114L,63115L,63116L,63117L,63118L,63119L,63120L,63121L,63122L,
8602163123L,63124L,63125L,63126L,63127L,63128L,63129L,63130L,63131L,63132L,
8602263133L,63134L,63135L,63136L,63137L,63138L,63139L,63140L,63141L,63142L,
8602363143L,63144L,63145L,63146L,63147L,63148L,63149L,63150L,63151L,63152L,
8602463153L,63154L,63155L,63156L,63157L,63158L,63159L,63160L,63161L,63162L,
8602563163L,63164L,63165L,63166L,63167L,63168L,63169L,63170L,63171L,63172L,
8602663173L,63174L,63175L,63176L,63177L,63178L,63179L,63180L,63181L,63182L,
8602763183L,63184L,63185L,63186L,63187L,63188L,63189L,63190L,63191L,63192L,
8602863193L,63194L,63195L,63196L,63197L,63198L,63199L,63200L,63201L,63202L,
8602963203L,63204L,63205L,63206L,63207L,63208L,63209L,63210L,63211L,63212L,
8603063213L,63214L,63215L,63216L,63217L,63218L,63219L,63220L,63221L,63222L,
8603163223L,63224L,63225L,63226L,63227L,63228L,63229L,63230L,63231L,63232L,
8603263233L,63234L,63235L,63236L,63237L,63238L,63239L,63240L,63241L,63242L,
8603363243L,63244L,63245L,63246L,63247L,63248L,63249L,63250L,63251L,63252L,
8603463253L,63254L,63255L,63256L,63257L,63258L,63259L,63260L,63261L,63262L,
8603563263L,63264L,63265L,63266L,63267L,63268L,63269L,63270L,63271L,63272L,
8603663273L,63274L,63275L,63276L,63277L,63278L,63279L,63280L,63281L,63282L,
8603763283L,63284L,63285L,63286L,63287L,63288L,63289L,63290L,63291L,63292L,
8603863293L,63294L,63295L,63296L,63297L,63298L,63299L,63300L,63301L,63302L,
8603963303L,63304L,63305L,63306L,63307L,63308L,63309L,63310L,63311L,63312L,
8604063313L,63314L,63315L,63316L,63317L,63318L,63319L,63320L,63321L,63322L,
8604163323L,63324L,63325L,63326L,63327L,63328L,63329L,63330L,63331L,63332L,
8604263333L,63334L,63335L,63336L,63337L,63338L,63339L,63340L,63341L,63342L,
8604363343L,63344L,63345L,63346L,63347L,63348L,63349L,63350L,63351L,63352L,
8604463353L,63354L,63355L,63356L,63357L,63358L,63359L,63360L,63361L,63362L,
8604563363L,63364L,63365L,63366L,63367L,63368L,63369L,63370L,63371L,63372L,
8604663373L,63374L,63375L,63376L,63377L,63378L,63379L,63380L,63381L,63382L,
8604763383L,63384L,63385L,63386L,63387L,63388L,63389L,63390L,63391L,63392L,
8604863393L,63394L,63395L,63396L,63397L,63398L,63399L,63400L,63401L,63402L,
8604963403L,63404L,63405L,63406L,63407L,63408L,63409L,63410L,63411L,63412L,
8605063413L,63414L,63415L,63416L,63417L,63418L,63419L,63420L,63421L,63422L,
8605163423L,63424L,63425L,63426L,63427L,63428L,63429L,63430L,63431L,63432L,
8605263433L,63434L,63435L,63436L,63437L,63438L,63439L,63440L,63441L,63442L,
8605363443L,63444L,63445L,63446L,63447L,63448L,63449L,63450L,63451L,63452L,
8605463453L,63454L,63455L,63456L,63457L,63458L,63459L,63460L,63461L,63462L,
8605563463L,63464L,63465L,63466L,63467L,63468L,63469L,63470L,63471L,63472L,
8605663473L,63474L,63475L,63476L,63477L,63478L,63479L,63480L,63481L,63482L,
8605763483L,63484L,63485L,63486L,63487L,63488L,63489L,63490L,63491L,63492L,
8605863493L,63494L,63495L,63496L,63497L,63498L,63499L,63500L,63501L,63502L,
8605963503L,63504L,63505L,63506L,63507L,63508L,63509L,63510L,63511L,63512L,
8606063513L,63514L,63515L,63516L,63517L,63518L,63519L,63520L,63521L,63522L,
8606163523L,63524L,63525L,63526L,63527L,63528L,63529L,63530L,63531L,63532L,
8606263533L,63534L,63535L,63536L,63537L,63538L,63539L,63540L,63541L,63542L,
8606363543L,63544L,63545L,63546L,63547L,63548L,63549L,63550L,63551L,63552L,
8606463553L,63554L,63555L,63556L,63557L,63558L,63559L,63560L,63561L,63562L,
8606563563L,63564L,63565L,63566L,63567L,63568L,63569L,63570L,63571L,63572L,
8606663573L,63574L,63575L,63576L,63577L,63578L,63579L,63580L,63581L,63582L,
8606763583L,63584L,63585L,63586L,63587L,63588L,63589L,63590L,63591L,63592L,
8606863593L,63594L,63595L,63596L,63597L,63598L,63599L,63600L,63601L,63602L,
8606963603L,63604L,63605L,63606L,63607L,63608L,63609L,63610L,63611L,63612L,
8607063613L,63614L,63615L,63616L,63617L,63618L,63619L,63620L,63621L,63622L,
8607163623L,63624L,63625L,63626L,63627L,63628L,63629L,63630L,63631L,63632L,
8607263633L,63634L,63635L,63636L,63637L,63638L,63639L,63640L,63641L,63642L,
8607363643L,63644L,63645L,63646L,63647L,63648L,63649L,63650L,63651L,63652L,
8607463653L,63654L,63655L,63656L,63657L,63658L,63659L,63660L,63661L,63662L,
8607563663L,63664L,63665L,63666L,63667L,63668L,63669L,63670L,63671L,63672L,
8607663673L,63674L,63675L,63676L,63677L,63678L,63679L,63680L,63681L,63682L,
8607763683L,63684L,63685L,63686L,63687L,63688L,63689L,63690L,63691L,63692L,
8607863693L,63694L,63695L,63696L,63697L,63698L,63699L,63700L,63701L,63702L,
8607963703L,63704L,63705L,63706L,63707L,63708L,63709L,63710L,63711L,63712L,
8608063713L,63714L,63715L,63716L,63717L,63718L,63719L,63720L,63721L,63722L,
8608163723L,63724L,63725L,63726L,63727L,63728L,63729L,63730L,63731L,63732L,
8608263733L,63734L,63735L,63736L,63737L,63738L,63739L,63740L,63741L,63742L,
8608363743L,63744L,63745L,63746L,63747L,63748L,63749L,63750L,63751L,63752L,
8608463753L,63754L,63755L,63756L,63757L,63758L,63759L,63760L,63761L,63762L,
8608563763L,63764L,63765L,63766L,63767L,63768L,63769L,63770L,63771L,63772L,
8608663773L,63774L,63775L,63776L,63777L,63778L,63779L,63780L,63781L,63782L,
8608763783L,63784L,63785L,63786L,63787L,63788L,63789L,63790L,63791L,63792L,
8608863793L,63794L,63795L,63796L,63797L,63798L,63799L,63800L,63801L,63802L,
8608963803L,63804L,63805L,63806L,63807L,63808L,63809L,63810L,63811L,63812L,
8609063813L,63814L,63815L,63816L,63817L,63818L,63819L,63820L,63821L,63822L,
8609163823L,63824L,63825L,63826L,63827L,63828L,63829L,63830L,63831L,63832L,
8609263833L,63834L,63835L,63836L,63837L,63838L,63839L,63840L,63841L,63842L,
8609363843L,63844L,63845L,63846L,63847L,63848L,63849L,63850L,63851L,63852L,
8609463853L,63854L,63855L,63856L,63857L,63858L,63859L,63860L,63861L,63862L,
8609563863L,63864L,63865L,63866L,63867L,63868L,63869L,63870L,63871L,63872L,
8609663873L,63874L,63875L,63876L,63877L,63878L,63879L,63880L,63881L,63882L,
8609763883L,63884L,63885L,63886L,63887L,63888L,63889L,63890L,63891L,63892L,
8609863893L,63894L,63895L,63896L,63897L,63898L,63899L,63900L,63901L,63902L,
8609963903L,63904L,63905L,63906L,63907L,63908L,63909L,63910L,63911L,63912L,
8610063913L,63914L,63915L,63916L,63917L,63918L,63919L,63920L,63921L,63922L,
8610163923L,63924L,63925L,63926L,63927L,63928L,63929L,63930L,63931L,63932L,
8610263933L,63934L,63935L,63936L,63937L,63938L,63939L,63940L,63941L,63942L,
8610363943L,63944L,63945L,63946L,63947L,63948L,63949L,63950L,63951L,63952L,
8610463953L,63954L,63955L,63956L,63957L,63958L,63959L,63960L,63961L,63962L,
8610563963L,63964L,63965L,63966L,63967L,63968L,63969L,63970L,63971L,63972L,
8610663973L,63974L,63975L,63976L,63977L,63978L,63979L,63980L,63981L,63982L,
8610763983L,63984L,63985L,63986L,63987L,63988L,63989L,63990L,63991L,63992L,
8610863993L,63994L,63995L,63996L,63997L,63998L,63999L,64000L,64001L,64002L,
8610964003L,64004L,64005L,64006L,64007L,64008L,64009L,64010L,64011L,64012L,
8611064013L,64014L,64015L,64016L,64017L,64018L,64019L,64020L,64021L,64022L,
8611164023L,64024L,64025L,64026L,64027L,64028L,64029L,64030L,64031L,64032L,
8611264033L,64034L,64035L,64036L,64037L,64038L,64039L,64040L,64041L,64042L,
8611364043L,64044L,64045L,64046L,64047L,64048L,64049L,64050L,64051L,64052L,
8611464053L,64054L,64055L,64056L,64057L,64058L,64059L,64060L,64061L,64062L,
8611564063L,64064L,64065L,64066L,64067L,64068L,64069L,64070L,64071L,64072L,
8611664073L,64074L,64075L,64076L,64077L,64078L,64079L,64080L,64081L,64082L,
8611764083L,64084L,64085L,64086L,64087L,64088L,64089L,64090L,64091L,64092L,
8611864093L,64094L,64095L,64096L,64097L,64098L,64099L,64100L,64101L,64102L,
8611964103L,64104L,64105L,64106L,64107L,64108L,64109L,64110L,64111L,64112L,
8612064113L,64114L,64115L,64116L,64117L,64118L,64119L,64120L,64121L,64122L,
8612164123L,64124L,64125L,64126L,64127L,64128L,64129L,64130L,64131L,64132L,
8612264133L,64134L,64135L,64136L,64137L,64138L,64139L,64140L,64141L,64142L,
8612364143L,64144L,64145L,64146L,64147L,64148L,64149L,64150L,64151L,64152L,
8612464153L,64154L,64155L,64156L,64157L,64158L,64159L,64160L,64161L,64162L,
8612564163L,64164L,64165L,64166L,64167L,64168L,64169L,64170L,64171L,64172L,
8612664173L,64174L,64175L,64176L,64177L,64178L,64179L,64180L,64181L,64182L,
8612764183L,64184L,64185L,64186L,64187L,64188L,64189L,64190L,64191L,64192L,
8612864193L,64194L,64195L,64196L,64197L,64198L,64199L,64200L,64201L,64202L,
8612964203L,64204L,64205L,64206L,64207L,64208L,64209L,64210L,64211L,64212L,
8613064213L,64214L,64215L,64216L,64217L,64218L,64219L,64220L,64221L,64222L,
8613164223L,64224L,64225L,64226L,64227L,64228L,64229L,64230L,64231L,64232L,
8613264233L,64234L,64235L,64236L,64237L,64238L,64239L,64240L,64241L,64242L,
8613364243L,64244L,64245L,64246L,64247L,64248L,64249L,64250L,64251L,64252L,
8613464253L,64254L,64255L,64256L,64257L,64258L,64259L,64260L,64261L,64262L,
8613564263L,64264L,64265L,64266L,64267L,64268L,64269L,64270L,64271L,64272L,
8613664273L,64274L,64275L,64276L,64277L,64278L,64279L,64280L,64281L,64282L,
8613764283L,64284L,64285L,64286L,64287L,64288L,64289L,64290L,64291L,64292L,
8613864293L,64294L,64295L,64296L,64297L,64298L,64299L,64300L,64301L,64302L,
8613964303L,64304L,64305L,64306L,64307L,64308L,64309L,64310L,64311L,64312L,
8614064313L,64314L,64315L,64316L,64317L,64318L,64319L,64320L,64321L,64322L,
8614164323L,64324L,64325L,64326L,64327L,64328L,64329L,64330L,64331L,64332L,
8614264333L,64334L,64335L,64336L,64337L,64338L,64339L,64340L,64341L,64342L,
8614364343L,64344L,64345L,64346L,64347L,64348L,64349L,64350L,64351L,64352L,
8614464353L,64354L,64355L,64356L,64357L,64358L,64359L,64360L,64361L,64362L,
8614564363L,64364L,64365L,64366L,64367L,64368L,64369L,64370L,64371L,64372L,
8614664373L,64374L,64375L,64376L,64377L,64378L,64379L,64380L,64381L,64382L,
8614764383L,64384L,64385L,64386L,64387L,64388L,64389L,64390L,64391L,64392L,
8614864393L,64394L,64395L,64396L,64397L,64398L,64399L,64400L,64401L,64402L,
8614964403L,64404L,64405L,64406L,64407L,64408L,64409L,64410L,64411L,64412L,
8615064413L,64414L,64415L,64416L,64417L,64418L,64419L,64420L,64421L,64422L,
8615164423L,64424L,64425L,64426L,64427L,64428L,64429L,64430L,64431L,64432L,
8615264433L,64434L,64435L,64436L,64437L,64438L,64439L,64440L,64441L,64442L,
8615364443L,64444L,64445L,64446L,64447L,64448L,64449L,64450L,64451L,64452L,
8615464453L,64454L,64455L,64456L,64457L,64458L,64459L,64460L,64461L,64462L,
8615564463L,64464L,64465L,64466L,64467L,64468L,64469L,64470L,64471L,64472L,
8615664473L,64474L,64475L,64476L,64477L,64478L,64479L,64480L,64481L,64482L,
8615764483L,64484L,64485L,64486L,64487L,64488L,64489L,64490L,64491L,64492L,
8615864493L,64494L,64495L,64496L,64497L,64498L,64499L,64500L,64501L,64502L,
8615964503L,64504L,64505L,64506L,64507L,64508L,64509L,64510L,64511L,64512L,
8616064513L,64514L,64515L,64516L,64517L,64518L,64519L,64520L,64521L,64522L,
8616164523L,64524L,64525L,64526L,64527L,64528L,64529L,64530L,64531L,64532L,
8616264533L,64534L,64535L,64536L,64537L,64538L,64539L,64540L,64541L,64542L,
8616364543L,64544L,64545L,64546L,64547L,64548L,64549L,64550L,64551L,64552L,
8616464553L,64554L,64555L,64556L,64557L,64558L,64559L,64560L,64561L,64562L,
8616564563L,64564L,64565L,64566L,64567L,64568L,64569L,64570L,64571L,64572L,
8616664573L,64574L,64575L,64576L,64577L,64578L,64579L,64580L,64581L,64582L,
8616764583L,64584L,64585L,64586L,64587L,64588L,64589L,64590L,64591L,64592L,
8616864593L,64594L,64595L,64596L,64597L,64598L,64599L,64600L,64601L,64602L,
8616964603L,64604L,64605L,64606L,64607L,64608L,64609L,64610L,64611L,64612L,
8617064613L,64614L,64615L,64616L,64617L,64618L,64619L,64620L,64621L,64622L,
8617164623L,64624L,64625L,64626L,64627L,64628L,64629L,64630L,64631L,64632L,
8617264633L,64634L,64635L,64636L,64637L,64638L,64639L,64640L,64641L,64642L,
8617364643L,64644L,64645L,64646L,64647L,64648L,64649L,64650L,64651L,64652L,
8617464653L,64654L,64655L,64656L,64657L,64658L,64659L,64660L,64661L,64662L,
8617564663L,64664L,64665L,64666L,64667L,64668L,64669L,64670L,64671L,64672L,
8617664673L,64674L,64675L,64676L,64677L,64678L,64679L,64680L,64681L,64682L,
8617764683L,64684L,64685L,64686L,64687L,64688L,64689L,64690L,64691L,64692L,
8617864693L,64694L,64695L,64696L,64697L,64698L,64699L,64700L,64701L,64702L,
8617964703L,64704L,64705L,64706L,64707L,64708L,64709L,64710L,64711L,64712L,
8618064713L,64714L,64715L,64716L,64717L,64718L,64719L,64720L,64721L,64722L,
8618164723L,64724L,64725L,64726L,64727L,64728L,64729L,64730L,64731L,64732L,
8618264733L,64734L,64735L,64736L,64737L,64738L,64739L,64740L,64741L,64742L,
8618364743L,64744L,64745L,64746L,64747L,64748L,64749L,64750L,64751L,64752L,
8618464753L,64754L,64755L,64756L,64757L,64758L,64759L,64760L,64761L,64762L,
8618564763L,64764L,64765L,64766L,64767L,64768L,64769L,64770L,64771L,64772L,
8618664773L,64774L,64775L,64776L,64777L,64778L,64779L,64780L,64781L,64782L,
8618764783L,64784L,64785L,64786L,64787L,64788L,64789L,64790L,64791L,64792L,
8618864793L,64794L,64795L,64796L,64797L,64798L,64799L,64800L,64801L,64802L,
8618964803L,64804L,64805L,64806L,64807L,64808L,64809L,64810L,64811L,64812L,
8619064813L,64814L,64815L,64816L,64817L,64818L,64819L,64820L,64821L,64822L,
8619164823L,64824L,64825L,64826L,64827L,64828L,64829L,64830L,64831L,64832L,
8619264833L,64834L,64835L,64836L,64837L,64838L,64839L,64840L,64841L,64842L,
8619364843L,64844L,64845L,64846L,64847L,64848L,64849L,64850L,64851L,64852L,
8619464853L,64854L,64855L,64856L,64857L,64858L,64859L,64860L,64861L,64862L,
8619564863L,64864L,64865L,64866L,64867L,64868L,64869L,64870L,64871L,64872L,
8619664873L,64874L,64875L,64876L,64877L,64878L,64879L,64880L,64881L,64882L,
8619764883L,64884L,64885L,64886L,64887L,64888L,64889L,64890L,64891L,64892L,
8619864893L,64894L,64895L,64896L,64897L,64898L,64899L,64900L,64901L,64902L,
8619964903L,64904L,64905L,64906L,64907L,64908L,64909L,64910L,64911L,64912L,
8620064913L,64914L,64915L,64916L,64917L,64918L,64919L,64920L,64921L,64922L,
8620164923L,64924L,64925L,64926L,64927L,64928L,64929L,64930L,64931L,64932L,
8620264933L,64934L,64935L,64936L,64937L,64938L,64939L,64940L,64941L,64942L,
8620364943L,64944L,64945L,64946L,64947L,64948L,64949L,64950L,64951L,64952L,
8620464953L,64954L,64955L,64956L,64957L,64958L,64959L,64960L,64961L,64962L,
8620564963L,64964L,64965L,64966L,64967L,64968L,64969L,64970L,64971L,64972L,
8620664973L,64974L,64975L,64976L,64977L,64978L,64979L,64980L,64981L,64982L,
8620764983L,64984L,64985L,64986L,64987L,64988L,64989L,64990L,64991L,64992L,
8620864993L,64994L,64995L,64996L,64997L,64998L,64999L,65000L,65001L,65002L,
8620965003L,65004L,65005L,65006L,65007L,65008L,65009L,65010L,65011L,65012L,
8621065013L,65014L,65015L,65016L,65017L,65018L,65019L,65020L,65021L,65022L,
8621165023L,65024L,65025L,65026L,65027L,65028L,65029L,65030L,65031L,65032L,
8621265033L,65034L,65035L,65036L,65037L,65038L,65039L,65040L,65041L,65042L,
8621365043L,65044L,65045L,65046L,65047L,65048L,65049L,65050L,65051L,65052L,
8621465053L,65054L,65055L,65056L,65057L,65058L,65059L,65060L,65061L,65062L,
8621565063L,65064L,65065L,65066L,65067L,65068L,65069L,65070L,65071L,65072L,
8621665073L,65074L,65075L,65076L,65077L,65078L,65079L,65080L,65081L,65082L,
8621765083L,65084L,65085L,65086L,65087L,65088L,65089L,65090L,65091L,65092L,
8621865093L,65094L,65095L,65096L,65097L,65098L,65099L,65100L,65101L,65102L,
8621965103L,65104L,65105L,65106L,65107L,65108L,65109L,65110L,65111L,65112L,
8622065113L,65114L,65115L,65116L,65117L,65118L,65119L,65120L,65121L,65122L,
8622165123L,65124L,65125L,65126L,65127L,65128L,65129L,65130L,65131L,65132L,
8622265133L,65134L,65135L,65136L,65137L,65138L,65139L,65140L,65141L,65142L,
8622365143L,65144L,65145L,65146L,65147L,65148L,65149L,65150L,65151L,65152L,
8622465153L,65154L,65155L,65156L,65157L,65158L,65159L,65160L,65161L,65162L,
8622565163L,65164L,65165L,65166L,65167L,65168L,65169L,65170L,65171L,65172L,
8622665173L,65174L,65175L,65176L,65177L,65178L,65179L,65180L,65181L,65182L,
8622765183L,65184L,65185L,65186L,65187L,65188L,65189L,65190L,65191L,65192L,
8622865193L,65194L,65195L,65196L,65197L,65198L,65199L,65200L,65201L,65202L,
8622965203L,65204L,65205L,65206L,65207L,65208L,65209L,65210L,65211L,65212L,
8623065213L,65214L,65215L,65216L,65217L,65218L,65219L,65220L,65221L,65222L,
8623165223L,65224L,65225L,65226L,65227L,65228L,65229L,65230L,65231L,65232L,
8623265233L,65234L,65235L,65236L,65237L,65238L,65239L,65240L,65241L,65242L,
8623365243L,65244L,65245L,65246L,65247L,65248L,65249L,65250L,65251L,65252L,
8623465253L,65254L,65255L,65256L,65257L,65258L,65259L,65260L,65261L,65262L,
8623565263L,65264L,65265L,65266L,65267L,65268L,65269L,65270L,65271L,65272L,
8623665273L,65274L,65275L,65276L,65277L,65278L,65279L,65280L,65281L,65282L,
8623765283L,65284L,65285L,65286L,65287L,65288L,65289L,65290L,65291L,65292L,
8623865293L,65294L,65295L,65296L,65297L,65298L,65299L,65300L,65301L,65302L,
8623965303L,65304L,65305L,65306L,65307L,65308L,65309L,65310L,65311L,65312L,
8624065313L,65314L,65315L,65316L,65317L,65318L,65319L,65320L,65321L,65322L,
8624165323L,65324L,65325L,65326L,65327L,65328L,65329L,65330L,65331L,65332L,
8624265333L,65334L,65335L,65336L,65337L,65338L,65339L,65340L,65341L,65342L,
8624365343L,65344L,65313L,65314L,65315L,65316L,65317L,65318L,65319L,65320L,
8624465321L,65322L,65323L,65324L,65325L,65326L,65327L,65328L,65329L,65330L,
8624565331L,65332L,65333L,65334L,65335L,65336L,65337L,65338L,65371L,65372L,
8624665373L,65374L,65375L,65376L,65377L,65378L,65379L,65380L,65381L,65382L,
8624765383L,65384L,65385L,65386L,65387L,65388L,65389L,65390L,65391L,65392L,
8624865393L,65394L,65395L,65396L,65397L,65398L,65399L,65400L,65401L,65402L,
8624965403L,65404L,65405L,65406L,65407L,65408L,65409L,65410L,65411L,65412L,
8625065413L,65414L,65415L,65416L,65417L,65418L,65419L,65420L,65421L,65422L,
8625165423L,65424L,65425L,65426L,65427L,65428L,65429L,65430L,65431L,65432L,
8625265433L,65434L,65435L,65436L,65437L,65438L,65439L,65440L,65441L,65442L,
8625365443L,65444L,65445L,65446L,65447L,65448L,65449L,65450L,65451L,65452L,
8625465453L,65454L,65455L,65456L,65457L,65458L,65459L,65460L,65461L,65462L,
8625565463L,65464L,65465L,65466L,65467L,65468L,65469L,65470L,65471L,65472L,
8625665473L,65474L,65475L,65476L,65477L,65478L,65479L,65480L,65481L,65482L,
8625765483L,65484L,65485L,65486L,65487L,65488L,65489L,65490L,65491L,65492L,
8625865493L,65494L,65495L,65496L,65497L,65498L,65499L,65500L,65501L,65502L,
8625965503L,65504L,65505L,65506L,65507L,65508L,65509L,65510L,65511L,65512L,
8626065513L,65514L,65515L,65516L,65517L,65518L,65519L,65520L,65521L,65522L,
8626165523L,65524L,65525L,65526L,65527L,65528L,65529L,65530L,65531L,65532L,
8626265533L,65534L,65535L,
86263};
86264#endif
7c673cae
FG
86265/*
86266 * Bitstream decoder.
86267 */
86268
86269/* include removed: duk_internal.h */
86270
86271/* Decode 'bits' bits from the input stream (bits must be 1...24).
86272 * When reading past bitstream end, zeroes are shifted in. The result
86273 * is signed to match duk_bd_decode_flagged.
86274 */
86275DUK_INTERNAL duk_int32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits) {
86276 duk_small_int_t shift;
86277 duk_uint32_t mask;
86278 duk_uint32_t tmp;
86279
86280 /* Note: cannot read more than 24 bits without possibly shifting top bits out.
86281 * Fixable, but adds complexity.
86282 */
86283 DUK_ASSERT(bits >= 1 && bits <= 24);
86284
86285 while (ctx->currbits < bits) {
86286#if 0
86287 DUK_DDD(DUK_DDDPRINT("decode_bits: shift more data (bits=%ld, currbits=%ld)",
86288 (long) bits, (long) ctx->currbits));
86289#endif
86290 ctx->currval <<= 8;
86291 if (ctx->offset < ctx->length) {
86292 /* If ctx->offset >= ctx->length, we "shift zeroes in"
86293 * instead of croaking.
86294 */
86295 ctx->currval |= ctx->data[ctx->offset++];
86296 }
86297 ctx->currbits += 8;
86298 }
86299#if 0
86300 DUK_DDD(DUK_DDDPRINT("decode_bits: bits=%ld, currbits=%ld, currval=0x%08lx",
86301 (long) bits, (long) ctx->currbits, (unsigned long) ctx->currval));
86302#endif
86303
86304 /* Extract 'top' bits of currval; note that the extracted bits do not need
86305 * to be cleared, we just ignore them on next round.
86306 */
86307 shift = ctx->currbits - bits;
86308 mask = (1 << bits) - 1;
86309 tmp = (ctx->currval >> shift) & mask;
86310 ctx->currbits = shift; /* remaining */
86311
86312#if 0
86313 DUK_DDD(DUK_DDDPRINT("decode_bits: %ld bits -> 0x%08lx (%ld), currbits=%ld, currval=0x%08lx",
86314 (long) bits, (unsigned long) tmp, (long) tmp, (long) ctx->currbits, (unsigned long) ctx->currval));
86315#endif
86316
86317 return tmp;
86318}
86319
86320DUK_INTERNAL duk_small_int_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx) {
86321 return (duk_small_int_t) duk_bd_decode(ctx, 1);
86322}
86323
86324/* Decode a one-bit flag, and if set, decode a value of 'bits', otherwise return
86325 * default value. Return value is signed so that negative marker value can be
86326 * used by caller as a "not present" value.
86327 */
86328DUK_INTERNAL duk_int32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value) {
86329 if (duk_bd_decode_flag(ctx)) {
86330 return (duk_int32_t) duk_bd_decode(ctx, bits);
86331 } else {
86332 return def_value;
86333 }
86334}
7c673cae
FG
86335/*
86336 * Bitstream encoder.
86337 */
86338
86339/* include removed: duk_internal.h */
86340
86341DUK_INTERNAL void duk_be_encode(duk_bitencoder_ctx *ctx, duk_uint32_t data, duk_small_int_t bits) {
86342 duk_uint8_t tmp;
86343
86344 DUK_ASSERT(ctx != NULL);
86345 DUK_ASSERT(ctx->currbits < 8);
86346
86347 /* This limitation would be fixable but adds unnecessary complexity. */
86348 DUK_ASSERT(bits >= 1 && bits <= 24);
86349
86350 ctx->currval = (ctx->currval << bits) | data;
86351 ctx->currbits += bits;
86352
86353 while (ctx->currbits >= 8) {
86354 if (ctx->offset < ctx->length) {
86355 tmp = (duk_uint8_t) ((ctx->currval >> (ctx->currbits - 8)) & 0xff);
86356 ctx->data[ctx->offset++] = tmp;
86357 } else {
86358 /* If buffer has been exhausted, truncate bitstream */
86359 ctx->truncated = 1;
86360 }
86361
86362 ctx->currbits -= 8;
86363 }
86364}
86365
86366DUK_INTERNAL void duk_be_finish(duk_bitencoder_ctx *ctx) {
86367 duk_small_int_t npad;
86368
86369 DUK_ASSERT(ctx != NULL);
86370 DUK_ASSERT(ctx->currbits < 8);
86371
86372 npad = (duk_small_int_t) (8 - ctx->currbits);
86373 if (npad > 0) {
86374 duk_be_encode(ctx, 0, npad);
86375 }
86376 DUK_ASSERT(ctx->currbits == 0);
86377}
7c673cae
FG
86378/*
86379 * Fast buffer writer with spare management.
86380 */
86381
86382/* include removed: duk_internal.h */
86383
86384/*
86385 * Macro support functions (use only macros in calling code)
86386 */
86387
86388DUK_LOCAL void duk__bw_update_ptrs(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t curr_offset, duk_size_t new_length) {
86389 duk_uint8_t *p;
86390
86391 DUK_ASSERT(thr != NULL);
86392 DUK_ASSERT(bw_ctx != NULL);
86393 DUK_UNREF(thr);
86394
86395 p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, bw_ctx->buf);
86396 DUK_ASSERT(p != NULL || (DUK_HBUFFER_DYNAMIC_GET_SIZE(bw_ctx->buf) == 0 && curr_offset == 0 && new_length == 0));
86397 bw_ctx->p = p + curr_offset;
86398 bw_ctx->p_base = p;
86399 bw_ctx->p_limit = p + new_length;
86400}
86401
86402DUK_INTERNAL void duk_bw_init(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_hbuffer_dynamic *h_buf) {
86403
86404 DUK_ASSERT(thr != NULL);
86405 DUK_ASSERT(bw_ctx != NULL);
86406 DUK_ASSERT(h_buf != NULL);
86407 DUK_UNREF(thr);
86408
86409 bw_ctx->buf = h_buf;
86410 duk__bw_update_ptrs(thr, bw_ctx, 0, DUK_HBUFFER_DYNAMIC_GET_SIZE(h_buf));
86411}
86412
86413DUK_INTERNAL void duk_bw_init_pushbuf(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t buf_size) {
86414 duk_context *ctx;
86415
86416 DUK_ASSERT(thr != NULL);
86417 DUK_ASSERT(bw_ctx != NULL);
86418 ctx = (duk_context *) thr;
86419
86420 (void) duk_push_dynamic_buffer(ctx, buf_size);
86421 bw_ctx->buf = (duk_hbuffer_dynamic *) duk_get_hbuffer(ctx, -1);
86422 duk__bw_update_ptrs(thr, bw_ctx, 0, buf_size);
86423}
86424
86425/* Resize target buffer for requested size. Called by the macro only when the
86426 * fast path test (= there is space) fails.
86427 */
86428DUK_INTERNAL duk_uint8_t *duk_bw_resize(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t sz) {
86429 duk_size_t curr_off;
86430 duk_size_t add_sz;
86431 duk_size_t new_sz;
86432
86433 DUK_ASSERT(thr != NULL);
86434 DUK_ASSERT(bw_ctx != NULL);
86435
86436 /* We could do this operation without caller updating bw_ctx->ptr,
86437 * but by writing it back here we can share code better.
86438 */
86439
86440 curr_off = (duk_size_t) (bw_ctx->p - bw_ctx->p_base);
86441 add_sz = (curr_off >> DUK_BW_SPARE_SHIFT) + DUK_BW_SPARE_ADD;
86442 new_sz = curr_off + sz + add_sz;
86443 if (new_sz < curr_off) {
86444 /* overflow */
11fdf7f2 86445 DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG);
7c673cae
FG
86446 return NULL; /* not reachable */
86447 }
86448#if 0 /* for manual torture testing: tight allocation, useful with valgrind */
86449 new_sz = curr_off + sz;
86450#endif
86451
86452 /* This is important to ensure dynamic buffer data pointer is not
86453 * NULL (which is possible if buffer size is zero), which in turn
86454 * causes portability issues with e.g. memmove() and memcpy().
86455 */
86456 DUK_ASSERT(new_sz >= 1);
86457
86458 DUK_DD(DUK_DDPRINT("resize bufferwriter from %ld to %ld (add_sz=%ld)", (long) curr_off, (long) new_sz, (long) add_sz));
86459
86460 duk_hbuffer_resize(thr, bw_ctx->buf, new_sz);
86461 duk__bw_update_ptrs(thr, bw_ctx, curr_off, new_sz);
86462 return bw_ctx->p;
86463}
86464
86465/* Make buffer compact, matching current written size. */
86466DUK_INTERNAL void duk_bw_compact(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx) {
86467 duk_size_t len;
86468
86469 DUK_ASSERT(thr != NULL);
86470 DUK_ASSERT(bw_ctx != NULL);
86471 DUK_UNREF(thr);
86472
86473 len = (duk_size_t) (bw_ctx->p - bw_ctx->p_base);
86474 duk_hbuffer_resize(thr, bw_ctx->buf, len);
86475 duk__bw_update_ptrs(thr, bw_ctx, len, len);
86476}
86477
86478DUK_INTERNAL void duk_bw_write_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len) {
86479 duk_uint8_t *p_base;
86480
86481 DUK_ASSERT(thr != NULL);
86482 DUK_ASSERT(bw != NULL);
86483 DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw));
86484 DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
86485 DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw));
86486 DUK_UNREF(thr);
86487
86488 p_base = bw->p_base;
86489 DUK_MEMCPY((void *) bw->p,
86490 (const void *) (p_base + src_off),
11fdf7f2 86491 (size_t) len);
7c673cae
FG
86492 bw->p += len;
86493}
86494
86495DUK_INTERNAL void duk_bw_write_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len) {
86496 DUK_ASSERT(thr != NULL);
86497 DUK_ASSERT(bw != NULL);
86498 DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw));
86499 DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
86500 DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw));
86501 DUK_UNREF(thr);
86502
86503 DUK_BW_ENSURE(thr, bw, len);
86504 duk_bw_write_raw_slice(thr, bw, src_off, len);
86505}
86506
86507DUK_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) {
86508 duk_uint8_t *p_base;
86509 duk_size_t buf_sz, move_sz;
86510
86511 DUK_ASSERT(thr != NULL);
86512 DUK_ASSERT(bw != NULL);
86513 DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw));
86514 DUK_ASSERT(buf != NULL);
86515 DUK_UNREF(thr);
86516
86517 p_base = bw->p_base;
86518 buf_sz = bw->p - p_base;
86519 move_sz = buf_sz - dst_off;
86520
86521 DUK_ASSERT(p_base != NULL); /* buffer size is >= 1 */
86522 DUK_MEMMOVE((void *) (p_base + dst_off + len),
86523 (const void *) (p_base + dst_off),
11fdf7f2 86524 (size_t) move_sz);
7c673cae
FG
86525 DUK_MEMCPY((void *) (p_base + dst_off),
86526 (const void *) buf,
11fdf7f2 86527 (size_t) len);
7c673cae
FG
86528 bw->p += len;
86529}
86530
86531DUK_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) {
86532 DUK_ASSERT(thr != NULL);
86533 DUK_ASSERT(bw != NULL);
86534 DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw));
86535 DUK_ASSERT(buf != NULL);
86536 DUK_UNREF(thr);
86537
86538 DUK_BW_ENSURE(thr, bw, len);
86539 duk_bw_insert_raw_bytes(thr, bw, dst_off, buf, len);
86540}
86541
86542DUK_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) {
86543 duk_uint8_t *p_base;
86544 duk_size_t buf_sz, move_sz;
86545
86546 DUK_ASSERT(thr != NULL);
86547 DUK_ASSERT(bw != NULL);
86548 DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw));
86549 DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw));
86550 DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
86551 DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw));
86552 DUK_UNREF(thr);
86553
86554 p_base = bw->p_base;
86555
86556 /* Don't support "straddled" source now. */
86557 DUK_ASSERT(dst_off <= src_off || dst_off >= src_off + len);
86558
86559 if (dst_off <= src_off) {
86560 /* Target is before source. Source offset is expressed as
86561 * a "before change" offset. Account for the memmove.
86562 */
86563 src_off += len;
86564 }
86565
86566 buf_sz = bw->p - p_base;
86567 move_sz = buf_sz - dst_off;
86568
86569 DUK_ASSERT(p_base != NULL); /* buffer size is >= 1 */
86570 DUK_MEMMOVE((void *) (p_base + dst_off + len),
86571 (const void *) (p_base + dst_off),
11fdf7f2 86572 (size_t) move_sz);
7c673cae
FG
86573 DUK_MEMCPY((void *) (p_base + dst_off),
86574 (const void *) (p_base + src_off),
11fdf7f2 86575 (size_t) len);
7c673cae
FG
86576 bw->p += len;
86577}
86578
86579DUK_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) {
86580 DUK_ASSERT(thr != NULL);
86581 DUK_ASSERT(bw != NULL);
86582 DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw));
86583 DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw));
86584 DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
86585 DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw));
86586 DUK_UNREF(thr);
86587
86588 /* Don't support "straddled" source now. */
86589 DUK_ASSERT(dst_off <= src_off || dst_off >= src_off + len);
86590
86591 DUK_BW_ENSURE(thr, bw, len);
86592 duk_bw_insert_raw_slice(thr, bw, dst_off, src_off, len);
86593}
86594
86595DUK_INTERNAL duk_uint8_t *duk_bw_insert_raw_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len) {
86596 duk_uint8_t *p_base, *p_dst, *p_src;
86597 duk_size_t buf_sz, move_sz;
86598
86599 DUK_ASSERT(thr != NULL);
86600 DUK_ASSERT(bw != NULL);
86601 DUK_ASSERT(off <= DUK_BW_GET_SIZE(thr, bw));
86602 DUK_UNREF(thr);
86603
86604 p_base = bw->p_base;
86605 buf_sz = bw->p - p_base;
86606 move_sz = buf_sz - off;
86607 p_dst = p_base + off + len;
86608 p_src = p_base + off;
11fdf7f2 86609 DUK_MEMMOVE((void *) p_dst, (const void *) p_src, (size_t) move_sz);
7c673cae
FG
86610 return p_src; /* point to start of 'reserved area' */
86611}
86612
86613DUK_INTERNAL duk_uint8_t *duk_bw_insert_ensure_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len) {
86614 DUK_ASSERT(thr != NULL);
86615 DUK_ASSERT(bw != NULL);
86616 DUK_ASSERT(off <= DUK_BW_GET_SIZE(thr, bw));
86617 DUK_UNREF(thr);
86618
86619 DUK_BW_ENSURE(thr, bw, len);
86620 return duk_bw_insert_raw_area(thr, bw, off, len);
86621}
86622
86623DUK_INTERNAL void duk_bw_remove_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len) {
86624 duk_size_t move_sz;
86625
86626 duk_uint8_t *p_base;
86627 duk_uint8_t *p_src;
86628 duk_uint8_t *p_dst;
86629
86630 DUK_ASSERT(thr != NULL);
86631 DUK_ASSERT(bw != NULL);
86632 DUK_ASSERT(off <= DUK_BW_GET_SIZE(thr, bw));
86633 DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
86634 DUK_ASSERT(off + len <= DUK_BW_GET_SIZE(thr, bw));
86635 DUK_UNREF(thr);
86636
86637 p_base = bw->p_base;
86638 p_dst = p_base + off;
86639 p_src = p_dst + len;
86640 move_sz = (duk_size_t) (bw->p - p_src);
86641 DUK_MEMMOVE((void *) p_dst,
86642 (const void *) p_src,
11fdf7f2 86643 (size_t) move_sz);
7c673cae
FG
86644 bw->p -= len;
86645}
86646
86647/*
86648 * Macro support functions for reading/writing raw data.
86649 *
86650 * These are done using mempcy to ensure they're valid even for unaligned
86651 * reads/writes on platforms where alignment counts. On x86 at least gcc
86652 * is able to compile these into a bswap+mov. "Always inline" is used to
86653 * ensure these macros compile to minimal code.
86654 *
86655 * Not really bufwriter related, but currently used together.
86656 */
86657
86658DUK_INTERNAL DUK_ALWAYS_INLINE duk_uint16_t duk_raw_read_u16_be(duk_uint8_t **p) {
86659 union {
86660 duk_uint8_t b[2];
86661 duk_uint16_t x;
86662 } u;
86663
11fdf7f2 86664 DUK_MEMCPY((void *) u.b, (const void *) (*p), (size_t) 2);
7c673cae
FG
86665 u.x = DUK_NTOH16(u.x);
86666 *p += 2;
86667 return u.x;
86668}
86669
86670DUK_INTERNAL DUK_ALWAYS_INLINE duk_uint32_t duk_raw_read_u32_be(duk_uint8_t **p) {
86671 union {
86672 duk_uint8_t b[4];
86673 duk_uint32_t x;
86674 } u;
86675
11fdf7f2 86676 DUK_MEMCPY((void *) u.b, (const void *) (*p), (size_t) 4);
7c673cae
FG
86677 u.x = DUK_NTOH32(u.x);
86678 *p += 4;
86679 return u.x;
86680}
86681
86682DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_raw_read_double_be(duk_uint8_t **p) {
86683 duk_double_union du;
86684 union {
86685 duk_uint8_t b[4];
86686 duk_uint32_t x;
86687 } u;
86688
11fdf7f2 86689 DUK_MEMCPY((void *) u.b, (const void *) (*p), (size_t) 4);
7c673cae
FG
86690 u.x = DUK_NTOH32(u.x);
86691 du.ui[DUK_DBL_IDX_UI0] = u.x;
11fdf7f2 86692 DUK_MEMCPY((void *) u.b, (const void *) (*p + 4), (size_t) 4);
7c673cae
FG
86693 u.x = DUK_NTOH32(u.x);
86694 du.ui[DUK_DBL_IDX_UI1] = u.x;
86695 *p += 8;
86696
86697 return du.d;
86698}
86699
86700DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_u16_be(duk_uint8_t **p, duk_uint16_t val) {
86701 union {
86702 duk_uint8_t b[2];
86703 duk_uint16_t x;
86704 } u;
86705
86706 u.x = DUK_HTON16(val);
11fdf7f2 86707 DUK_MEMCPY((void *) (*p), (const void *) u.b, (size_t) 2);
7c673cae
FG
86708 *p += 2;
86709}
86710
86711DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_u32_be(duk_uint8_t **p, duk_uint32_t val) {
86712 union {
86713 duk_uint8_t b[4];
86714 duk_uint32_t x;
86715 } u;
86716
86717 u.x = DUK_HTON32(val);
11fdf7f2 86718 DUK_MEMCPY((void *) (*p), (const void *) u.b, (size_t) 4);
7c673cae
FG
86719 *p += 4;
86720}
86721
86722DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_double_be(duk_uint8_t **p, duk_double_t val) {
86723 duk_double_union du;
86724 union {
86725 duk_uint8_t b[4];
86726 duk_uint32_t x;
86727 } u;
86728
86729 du.d = val;
86730 u.x = du.ui[DUK_DBL_IDX_UI0];
86731 u.x = DUK_HTON32(u.x);
11fdf7f2 86732 DUK_MEMCPY((void *) (*p), (const void *) u.b, (size_t) 4);
7c673cae
FG
86733 u.x = du.ui[DUK_DBL_IDX_UI1];
86734 u.x = DUK_HTON32(u.x);
11fdf7f2 86735 DUK_MEMCPY((void *) (*p + 4), (const void *) u.b, (size_t) 4);
7c673cae
FG
86736 *p += 8;
86737}
7c673cae
FG
86738/*
86739 * Hash function duk_util_hashbytes().
86740 *
86741 * Currently, 32-bit MurmurHash2.
86742 *
86743 * Don't rely on specific hash values; hash function may be endianness
86744 * dependent, for instance.
86745 */
86746
86747/* include removed: duk_internal.h */
86748
11fdf7f2 86749#if defined(DUK_USE_STRHASH_DENSE)
7c673cae
FG
86750/* 'magic' constants for Murmurhash2 */
86751#define DUK__MAGIC_M ((duk_uint32_t) 0x5bd1e995UL)
86752#define DUK__MAGIC_R 24
86753
86754DUK_INTERNAL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed) {
86755 duk_uint32_t h = seed ^ ((duk_uint32_t) len);
86756
86757 while (len >= 4) {
86758 /* Portability workaround is required for platforms without
86759 * unaligned access. The replacement code emulates little
86760 * endian access even on big endian architectures, which is
86761 * OK as long as it is consistent for a build.
86762 */
86763#ifdef DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS
11fdf7f2 86764 duk_uint32_t k = *((const duk_uint32_t *) (const void *) data);
7c673cae
FG
86765#else
86766 duk_uint32_t k = ((duk_uint32_t) data[0]) |
86767 (((duk_uint32_t) data[1]) << 8) |
86768 (((duk_uint32_t) data[2]) << 16) |
86769 (((duk_uint32_t) data[3]) << 24);
86770#endif
86771
86772 k *= DUK__MAGIC_M;
86773 k ^= k >> DUK__MAGIC_R;
86774 k *= DUK__MAGIC_M;
86775 h *= DUK__MAGIC_M;
86776 h ^= k;
86777 data += 4;
86778 len -= 4;
86779 }
86780
86781 switch (len) {
86782 case 3: h ^= data[2] << 16;
86783 case 2: h ^= data[1] << 8;
86784 case 1: h ^= data[0];
86785 h *= DUK__MAGIC_M;
86786 }
86787
86788 h ^= h >> 13;
86789 h *= DUK__MAGIC_M;
86790 h ^= h >> 15;
86791
86792 return h;
86793}
11fdf7f2 86794#endif /* DUK_USE_STRHASH_DENSE */
7c673cae
FG
86795/*
86796 * A tiny random number generator.
86797 *
86798 * Currently used for Math.random().
86799 *
86800 * http://www.woodmann.com/forum/archive/index.php/t-3100.html
86801 */
86802
86803/* include removed: duk_internal.h */
86804
86805#define DUK__UPDATE_RND(rnd) do { \
86806 (rnd) += ((rnd) * (rnd)) | 0x05; \
86807 (rnd) = ((rnd) & 0xffffffffU); /* if duk_uint32_t is exactly 32 bits, this is a NOP */ \
86808 } while (0)
86809
86810#define DUK__RND_BIT(rnd) ((rnd) >> 31) /* only use the highest bit */
86811
86812DUK_INTERNAL duk_uint32_t duk_util_tinyrandom_get_bits(duk_hthread *thr, duk_small_int_t n) {
86813 duk_small_int_t i;
86814 duk_uint32_t res = 0;
86815 duk_uint32_t rnd;
86816
86817 rnd = thr->heap->rnd_state;
86818
86819 for (i = 0; i < n; i++) {
86820 DUK__UPDATE_RND(rnd);
86821 res <<= 1;
86822 res += DUK__RND_BIT(rnd);
86823 }
86824
86825 thr->heap->rnd_state = rnd;
86826
86827 return res;
86828}
86829
86830DUK_INTERNAL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr) {
86831 duk_double_t t;
86832 duk_small_int_t n;
86833 duk_uint32_t rnd;
86834
86835 /*
86836 * XXX: could make this a lot faster if we create the double memory
86837 * representation directly. Feasible easily (must be uniform random).
86838 */
86839
86840 rnd = thr->heap->rnd_state;
86841
86842 n = 53; /* enough to cover the whole mantissa */
86843 t = 0.0;
86844
86845 do {
86846 DUK__UPDATE_RND(rnd);
86847 t += DUK__RND_BIT(rnd);
86848 t /= 2.0;
86849 } while (--n);
86850
86851 thr->heap->rnd_state = rnd;
86852
86853 DUK_ASSERT(t >= (duk_double_t) 0.0);
86854 DUK_ASSERT(t < (duk_double_t) 1.0);
86855
86856 return t;
86857}